Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a reinterpret_cast change the object representation?

My mental model for a reinterpret_cast has always been, to treat the sequence of bits of an expression as if they were of a different type, and cppreference (note: this is not a quote from the C++ Standard) seems to agree with that:

Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions. It is purely a compiler directive which instructs the compiler to treat the sequence of bits (object representation) of expression as if it had the type new_type.

Looking for guarantees, I stumbled across a note under [expr.reinterpret.cast]:

[ Note: The mapping performed by reinterpret_­cast might, or might not, produce a representation different from the original value. — end note ]

That left me wondering: Under which conditions does a reinterpret_cast produce a value with object representation different from the original value?

like image 353
IInspectable Avatar asked Aug 25 '18 21:08

IInspectable


1 Answers

Here's an example: if you read the 4th bullet point:

A pointer can be explicitly converted to any integral type large enough to hold all values of its type. The mapping function is implementation-defined. [ Note: It is intended to be unsurprising to those who know the addressing structure of the underlying machine. — end note ]

Now, it is implementation defined, what value of i will have here:

void *ptr = <some valid pointer value>;
uintptr_t i = reinterpret_cast<uintptr_t>(ptr);

It can be anything, provided that reinterpret_casting i back we'll get ptr.

The representation of ptr and i could differ. The standard just says that the value of i should be "unsurprising". Even, if we reinterpret_cast ptr to a wider integer (for example, if a pointer is 32-bit, casting to unsigned long long int), the representation must differ, because the size of the variables differ.

So I think that cppreference description is misleading, because there can be reinterpret_casts, which actually need CPU instructions.


Here is another case (found by IInspectable), a comment by Keith Thompson:

The C compiler for Cray vector machines, such as the T90, do something similar. Hardware addresses are 8 bytes, and point to 8-byte words. void* and char* are handled in software, and are augmented with a 3-bit offset within the word -- but since there isn't actually a 64-bit address space, the offset is stored in the high-order 3 bits of the 64-bit word. So char* and int* are the same size, but have different internal representations -- and code that assumes that pointers are "really" just integers can fail badly.

char * and int * have different representations on Cray T90, so:

int *i = <some int pointer value>;
char *c = reinterpret_cast<char *>(i);

Here, i and c will have differing representations on Cray T90 (and doing this conversion definitely uses CPU instructions).

(I've verified this, chapter 3.1.2.7.1 of Cray C/C++ Reference Manual SR–2179 2.0)

like image 186
geza Avatar answered Sep 30 '22 17:09

geza