Pointers are integral types. It's entirely fine to store a pointer in any integral type that is large enough to contain it. For example, the following is perfectly valid C:
double f()
{
double a = 10.5;
uintptr_t p = (uintptr_t)(&a);
double * q = (double *)p;
return *q;
}
By contrast, the following is a clear aliasing violation:
short buf[100] = {};
double x = *(double*)(buf + 13);
The point is that it doesn't matter how you store your pointer values. What matters is that you must only treat those pointers as pointers to an object that are actually pointers to an object of the correct type.
In the first example, p
does really store the pointer to a double, although it is not itself a double *
. In the second example, buf + 13
is simply not a pointer to a double, so dereferencing it as such is type punning, and an aliasing violation.
(Pointers and casts are one of the reasons that C is not a safe language: The correctness of an operation can depend on the value of a variable, rather than just its type.)