问题
For example, consider the following C code snippet:
void *p = malloc(1);
void *q = malloc(1);
bool question = (uintptr_t) p == (uintptr_t) q;
I expect everyone expects question
be always false. (Surprisingly, the C11 standard does not require it, though. The only restriction on uintptr_t
is e.g. ((void *) ((uintptr_t) p)) == p
. See 7.20.1.4 of the C11 standard for details.)
My question is: is there any realistic use case that actually relies on the guarantee that question
be false, or more generally, the integer representations of two allocations be different?
回答1:
The question is flawed. First, consider this code (where we suppose that malloc
does not return null):
void *p = malloc(1);
void *q = malloc(1);
bool question = (uintptr_t) p == (uintptr_t) q;
Per the C 2011 standard’s specification of uintptr_t
, if we do:
void *p1 = (void *) (uintptr_t) p;
void *q1 = (void *) (uintptr_t) q;
Then p1
must compare equal to p
, and q1
must compare equal to q
. And, per the standard’s specification of the ==
operator, p1
and q1
must not compare equal to each other, since they are, respectively, equal to p
and to q
, and hence are pointers to different objects.
Because (void *) (uintptr_t) p
and (void *) (uintptr_t) q
produce different values, (uintptr_t) p
and (uintptr_t) q
must be different values. (This is because the conversion to void *
is a mathematical function within the C model. Every time it is given a specific value, within the rules of C, it produces a result that is effectively the same, within the rules of C.) Therefore (uintptr_t) p
is not equal to (uintptr_t) q
.
Now consider this code, where we change void *
to char *
:
char *p = malloc(1);
char *q = malloc(1);
bool question = (uintptr_t) p == (uintptr_t) q;
The specification of uintptr_t
is silent about conversions from char *
. Obviously, these pointers to char *
can be converted to void *
. However, I do not see that the standard requires that a conversion from char *
to uintptr_t
must implicitly insert a conversion to void *
or act as if it did. So I suppose this is technically undefined by the standard. But I doubt you will find any C implementation in which this differs from the void *
version, except one constructed specifically to violate this.
Nonetheless, effectively every programmer that uses uintptr_t
expects the result to fully identify the original pointer (it contains all the information to convert back to the original pointer), and hence they expect the uintptr_t
result to differ from that of all different pointers.
As for one specific example, the Accelerate framework in macOS expects the result of converting different pointers to uintptr_t
to produce different results, and I am sure many other parts of macOS do too.
来源:https://stackoverflow.com/questions/47481834/are-there-any-use-cases-relying-on-integer-representation-of-two-allocations-bei