I wonder if C++ implementations are allowed to represent pointers to different types differently. For instance, if we had 4-byte sized/aligned int
and 8-byte sized/aligned long
, would it be possible to represent pointers-to-int
/long
as object addresses shifted right by 2/3 bits, respectively? This would effectively forbid to convert a pointer-to-long
into a pointer-to-int
.
I am asking because of [expr.reinterpret.cast/7]:
An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue
v
of object pointer type is converted to the object pointer type “pointer to cvT
”, the result isstatic_cast<cv T*>(static_cast<cv void*>(v))
.[Note 7: Converting a pointer of type “pointer to
T1
” that points to an object of typeT1
to the type “pointer toT2
” (whereT2
is an object type and the alignment requirements ofT2
are no stricter than those ofT1
) and back to its original type yields the original pointer value. — end note]
The first sentence suggests that we can convert pointers to any two object types. However, the empathized text in the (not normative) Note 7 then says that the alignment plays some role here as well. (That's why I came up with that int
-long
example above.)
Yep
As a concrete example, there is a C++ implementation where pointers to single-byte elements are larger than pointers to multi-byte elements, because the hardware uses word (not byte) addressing. To emulate byte pointers, C++ uses a hardware pointer plus an extra byte offset.
void*
stores that extra offset, butint*
does not. Convertingint*
tochar*
works (as it must under the standard), butchar*
toint*
loses that offset (which your note implicitly permits).The Cray T90 supercomputer is an example of such hardware.
I will see if I can find the standards argument why this is valid thing for a compliant C++ compiler to do; I am only aware someone did it, not that it is legal to do it, but that note rather implies it is intended to be legal.
The rules are going to be in the to-from void pointer casting rules. The paragraph you quoted implicitly forwards the meaning of the conversion to there.
7.6.1.9 Static cast [expr.static.cast]
This demonstrates that converting to more-aligned types generates an unspecified pointer, but converting to equal-or-less aligned types that aren't actually there does not change the pointer value.
Which is permission to make a cast from a pointer to 4 byte aligned data converted to a pointer to 8 byte aligned data result in garbage.
Every object unrelated pointer cast needs to logically round-trip through a
void*
however.(From the OP)
That covers
void*
toT*
; I have yet to find theT*
tovoid*
conversion text to make this a complete language-lawyer level answer.