C – Conversion to void* Before Converting to uintptr_t

c++c99castinglanguage-lawyervoid-pointers

Section 7.18.1.4 of the C99 standard states:

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

uintptr_t

Does this mean that only void * types can be converted to uintptr_t and back without changing the value of the original pointer?

In particular, I would like to know if the following code is required to use uintptr_t:

int foo = 42;
void * bar = &foo;
uintptr_t baz = bar;
void * qux = baz;
int quux = *(int *)qux; /* quux == foo == 42 */

Or if this simpler version is guaranteed by the C99 standard to result in the same effect:

int foo = 42;
uintptr_t bar = &foo;
int baz = *(int *)bar; /* baz == foo == 42 */

Is a conversion to void * required before converting a pointer to uintptr_t and vice versa?

Best Answer

The distinction exists also because while any pointer to an object can be converted to void *, C doesn't require that function pointers can be converted to void * and back again!

As for pointers to objects of other types, the C standard says that any pointer can be converted to an integer, and an integer can be converted to any pointer, but such results are implementation-defined. Since the standard says that only void * is convertible back and forth, the safest bet is to cast the pointer to void * first, as it might be that pointers that have different representations when converted to uintptr_t will result in a different integer representation too, so it could be conceivable that:

int a;
uintptr_t up = (uintptr_t)&a;
void *p = (void *)up;
p == &a; // could be conceivably false, or it might be even that the value is indeterminate.