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 tovoid
, 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?
The intptr_t and uintptr_t types are extremely useful for casting pointers when you want to do address arithmetic. They should be used instead of long or unsigned long for this purpose.
A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address.
The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means that it points to the address of variables. It is also called the general purpose pointer.
Yes an intermediate conversion to void*
is required for this to be portable. This is because pointer to integer conversion is "implementation defined", so your platform could do anything as long as they document it.
BTW, you are mixing up "cast" and "conversion" in your question. "Conversion" is the more general term, "cast" is "explicit conversion".
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.
There are various places where the authors of the Standard didn't think it necessary to mandate that compilers behave sensibly, because they expected compilers to do so anyhow.
If an implementation defines uintptr_t
and p
is a void*
, the only thing the Standard mandates about void *q = (void*)(uintptr_t)p;
is that q==p
will compare equal. The Standard does not guarantee that q
will be usable for any particular purposes for which p
would have been usable, or even for any purpose other than comparisons with other pointers.
From a practical perspective, there's no reason an implementation should require casting to/from void*
on either side of conversions through uintptr_t
, but the Standard would allow implementations to behave in arbitrary fashion if such extra casts were omitted. On the other hand, since the Standard would also allow implementations to behave in arbitrary fashion in nearly all practical situations
involving uintptr_t
, the only real question is whether one is willing to rely upon implementers not to behave in obtuse fashion. Such reliance may be reasonable with some commercial compilers, but not so much with some free ones.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With