Hi!

I recently tried to add sentinel attributes to the beast code, and found
that the way gcc treats sentinels right now, we need to make a trade off
between type safety against the sentinel NULL termination check. The
GNOME bugzilla link is here:

  http://bugzilla.gnome.org/show_bug.cgi?id=344388

But I made a little self contained example, so you can see the problem
right here:

#include <stdio.h>
#include <stdarg.h>

static void print_string_array (const char *array_name,
                                const char *string, ...) __attribute__ 
((__sentinel__));

static void
print_string_array (const char *array_name,
                    const char *string, ...) 
{
  va_list ap;
  printf ("strings in %s = [", array_name);
  for (va_start (ap, string); string; string = va_arg (ap, const char *))
    printf (" '%s'", string);
  va_end(ap);
  printf (" ];\n");
}

int
main()
{
  print_string_array ("foo_array", "string1", "string2", "string3", NULL);
  print_string_array ("empty_array", NULL); /* gcc warns, but shouldn't */
  return 0;
}

The program compiles and runs like this:

[EMAIL PROTECTED]:~/tmp$ gcc -o fmt-sentinel fmt-sentinel.c -Wall
fmt-sentinel.c: In function 'main':
fmt-sentinel.c:23: warning: not enough variable arguments to fit a sentinel
[EMAIL PROTECTED]:~/tmp$ fmt-sentinel
strings in foo_array = [ 'string1' 'string2' 'string3' ];
strings in empty_array = [ ];
[EMAIL PROTECTED]:~/tmp$ 

So you see, although we think the second call of print_string_array is
correct (and makes sense in this toy program), gcc doesn't, because the
NULL sentinel doesn't occur within the varargs section of the parameter
list.

The only way out for keeping the sentinel attribute and avoiding the
warning is using

static void print_string_array (const char *array_name, ...) __attribute__ 
((__sentinel__));

as function prototype, so that the first string also becomes one of the
varargs arguments. But this makes the code less typesafe, because then
the compiler can no longer check that the first "string" argument the
caller passes is really a "const char *".

I was wondering if the sentinel attribute could be modified or extended
in a way that we don't need to trade type safety against NULL
termination check, but can have both?

By the way, there is already an existing gcc bug, which is about the
same thing (NULL passed within named args), but wants to have it the way
it works now:

  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21911

so if it gets changed, then gcc might need to support both
 - NULL termination within the last named parameter allowed
 - NULL termination only allowed within varargs parameters (like it is
   now)

   Cu... Stefan
-- 
Stefan Westerfeld, Hamburg/Germany, http://space.twc.de/~stefan

Reply via email to