[regarding hashing pointers by first converting them to uintptr_t]
Assume the following:
void *p1 = foo();
void *p2 = bar();
uintptr_t u1 = uintptr_t(p1);
uintptr_t u2 = uintptr_t(p1);
Minor nit: this is (old) C++ syntax; you mean:
uintptr_t u1 = (uintptr_t)p1;
and so on.
Assume that p1 == p2 (they point to the same address), but that they
have different internal representations (perhaps one is normalized and
the other is not).
We know from C99 7.18.1.4 that (void*)u1 == (void*)u2, but we don't
know that u1 == u2. For example, if the cast simply copies the bits,
the values of u1 and u2 would reflect the difference in
representations of the two pointer values; converting back to void*
yields two pointers that have different representations, but compare
equal to each other.
The cast *might* normalize the representation, but it doesn't have to.
Indeed, consider the historical implementations that are the very
reason the C standards are full of this kind of weirdness with
pointer arithmetic. In other words, think back to the 1980s and
C compilers for the IBM PC that ran under MS-DOS with its various
"extender" schemes to access more than 64K and 640K of memory.
One of the models under which code ran had 20-bit pointers, so that
uintptr_t would have to be defined as "unsigned long" ("int" being
only 16 bits on these compilers). If functions foo() and bar()
returned "un-normalized" pointers, and you assigned these to u1 and
u2 via casts, you get -- unnormalized integers. The "normalization"
operation was done by the "==" operators (only). Relational
comparisons ("<" and ">", and their "<=" and ">=" variants) compared
only offsets. This led to the peculiar case that:
printf("p1 is %sequal to p2\n", p1 == p2 ? "" : "not ");
printf("p1 is %sless than p2\n", p1 < p2 ? "" : "not ");
would sometimes print:
p1 is equal to p2
p1 is less than p2
In other words, p1 < p2 && p1 == p2, both at the same time.
(The only things that behave this way on modern CPUs are floating
point numbers.
If x is set to NaN, a surprising number of
comparisons all produce "false" as their result.)