On 04/25/2013 05:18 PM, Werner Wenzel wrote:
> Am 25.04.2013 21:19, schrieb Keith Thompson:
...
>> For any integer type, the object representation where all the bits
>> are zero shall be a representation of the value zero in that type.
>>
>> That was added by one of the Technical Corrigenda to C99.
>>
>> (There's no such requirement for pointer or floating-point types.
>>
>> At least for pointers, there could be a very good reason to make null
>> something other than all-bits-zero. I once worked on a (non-C) system
>> that used 0x00000001 as its null pointer representation because the
>> hardware would trap on an attempt to dereference an odd address (at
>> least for types bigger than one byte).
>>
> Does this still hold?
>
> The C11 standard (actually N1570 Committee Draft April 12, 2011) says in
> paragraph 6.3.2.3 Pointers, #3: "An integer constant expression with the
> value 0, or such an expression cast to type void *, is called a null
> pointer constant."
>
> And in footnote #66: "The macro NULL is defined in <stddef.h> (and other
> headers) as a null pointer constant; see 7.19."
That's not a change from C99, and there's no contradiction here. A null
pointer constant, if used in various contexts, gets implicitly converted
to a null pointer. That null pointer, if saved in a pointer object, will
have a representation. Just because the null pointer constant
necessarily involves a integer expression with a value of 0 doesn't mean
that representation of null pointer must have all bits 0.
#include <assert.h>
int main(void)
{
void *p = 0;
int i = 0;
void *q = (void*)i;
unsigned char array[sizeof p] = {0};
assert(p==q);
// If we've reached this point, q is a null pointer.
assert(memcmp(&p, &q, sizeof p));
assert(memcmp(&p, array, sizeof p));
return 0
}
Note that i is an integer expression with a value of zero, but it is not
an integer constant expression, because 'i' doesn't qualify as any of
the things allowed by 6.6p6 in integer constant expressions. Therefore,
there is no null pointer constant here involved in the initialization of
q. The value of (void*)0 is therefore governed only by 6.3.2.3p5, which
allows, among other things, the possibility that q might have a trap
representation. Even if it isn't, it need not be a null pointer.
If q has a trap representation, the first assert() has undefined
behavior before it even gets a chance to be triggered. Even if that's
not the case, the C standard says nothing that prevents any of those
asserts from triggering.
> (Although paragraph 7.19 Common definitions <stddef.h>, #3, describes
> NULL as an "implementation-defined" null pointer constant.)
That's true. NULL can expand into 0, '\0', 0U, 0L, L'\0', (5-5), or
((short)3.14F - (long)3.41), (void*)0, among infinitely many other
possibilities. I don't know of any good reason for defining it as
anything other than 0 or (void*)0, but all of those other definitions
are allowed.