This is a "according to the very words of the C-Standard"-Question. Is it guaranteed, that a cast from NULL to an unsigned integer, big enough to hold any pointer, results in the same value, irrespectively of the type of the pointer, that holds NULL?
Please see the following piece of code, where T1, T2 might be of any type constructable in C:
/* unsigned int be known to be big enough to hold any object pointer */
unsigned int ui_ptr1, ui_ptr2, ui_ptr3, res;
ui_ptr1 = (unsigned int) NULL;
ui_ptr2 = (unsigned int) (T1 *) NULL;
ui_ptr3 = (unsigned int) (T2 *) NULL;
res = (ui_ptr1 == ui_ptr2) && (ui_ptr1 == ui_ptr3);
From C99 and C11, 22.214.171.124 p3:
An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
(Also, footnote 56/67 remarks that "The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment").
(A draft of C89 has the equivalent text to the C99 quoted above in section 126.96.36.199).
So, it seems fairly safe to assume, on an architecture with a linear addressing scheme and where the pointer size is equal to the word size, that a single integer value represents
NULL - especially if you go through the
void * type. In theory though, a
NULL pointer (even
void *) when converted to an integer might not equal 0, since that's not mandated. You can get around this by always converting through
void * before comparing whether the value represents
That is, if you change your above declarations of ui_ptr2 and ui_ptr3 to:
ui_ptr2 = (unsigned int) (void *) (T1 *) NULL; ui_ptr3 = (unsigned int) (void *) (T2 *) NULL;
... then you can at least be sure that each of:
(void *) ui_ptr2 == (void *) ui_ptr3 (void *) ui_ptr2 == NULL (void *) ui_ptr3 == NULL
... will be true. If you cast either
(void *) ui_ptr2 or
(void *) ui_ptr3 to some other pointer type, it should still be
NULL, as per 188.8.131.52 p4 quoted above.
You are, however, relying on the conversion of pointer-to-integer being reversible. The conversion is implementation defined, in both directions, and though one would hope that converting a pointer to an integer and then back to a pointer yields the original pointer value, that's not strictly mandated (though footnote 56 quoted above strongly recommends it by implication). Furthermore there is no guarantee that all possible pointer values are representable in any integer type (184.108.40.206 p6). Your only real way around this is to verify that
sizeof(int) >= sizeof(void *) and then use
memcpy to transfer the representation of the pointer to the integer, and back, in which case there is no longer a need to go via
void * (just so long as the type of the pointer you store is the same as the type you retrieve).