[PATCH] Fixes sentinel warnings on GCC4

Karl Hegbloom hegbloom at pdx.edu
Tue Dec 6 19:34:04 EST 2005


On Tue, 2005-12-06 at 16:07 -0500, Chris Shoemaker wrote:
> Yes, this *works*!  IFF NULL expands to "0".  But, it's not portable
> because NULL *may* expand to (void*)0.  This is *exactly* why using
> "NULL" (or even "0") as a sentinel is not portable.  Portable code
> *must* explicitly cast sentinels.  Don't blame me - blame Ritchie.
> 
> Remember: arguments to variadic functions are NOT in a pointer
> context. 

After reading what Stuart D. Gathman wrote in this thread, I'm thinking
that it's not Ritchie's fault either.  It's a matter of mapping the C
language to the hardware and it's assembly language.

I was going to respond that I think it's BS to have to cast the NULL
pointer, but now I see why it is necessary.  It does have to do with
context.  If it's a pointer to a type where the pointer is 8 bits, and
the stdarg code expects a (void *)0 that turns out to be 32 bits... the
input argument is not automatically extended to 32 bits because the
compiler cannot see the need for it unless you tell it with the cast or
an assignment to a variable with a larger sized pointer type.

We probably should not even assume that (equalp NULL 0).  Maybe it's
0xff?  In either case, the explicit cast to (void *) will port, right?

Q: Why can't the stdarg.h code perform that typecast internally so that
client code does not have to?

And... from info libc, on variadic functions:

8<------------------------------------------------------------------------>8
        Since the prototype doesn't specify types for optional
        arguments, in a call to a variadic function the default argument
        promotions are performed on the optional argument values. This
        means the objects of type char or short int (whether signed or
        not) are promoted to either int or unsigned int, as appropriate;
        and that objects of type float are promoted to type double. So,
        if the caller passes a char as an optional argument, it is
        promoted to an int, and the function can access it with va_arg
        (ap, int). 

        Conversion of the required arguments is controlled by the
        function prototype in the usual way: the argument expression is
        converted to the declared argument type as if it were being
        assigned to a variable of that type. 
8<------------------------------------------------------------------------>8

It says that this "default argument promotions" feature is required by
ISO C.  So shouldn't a small pointer type be promoted automatically to a
larger pointer type, by the compiler?  (Of course it cannot happen at
run-time in C.)

What settles it once and for all is this, from info libc, "The NULL
Pointer Constant":

8<------------------------------------------------------------------------>8
        If you use the null pointer constant as a function argument,
        then for complete portability you should make sure that the
        function has a prototype declaration. Otherwise, if the target
        machine has two different pointer representations, the compiler
        won't know which representation to use for that argument. You
        can avoid the problem by explicitly casting the constant to the
        proper pointer type, but we recommend instead adding a prototype
        for the function you are calling.
8<------------------------------------------------------------------------>8

-- 
Karl Hegbloom <hegbloom at pdx.edu>



More information about the gnucash-devel mailing list