1

cppreference/reinterpret_cast conversion/Explanation says

Unlike static_cast, but like const_cast, the reinterpret_cast expression does not compile to any CPU instructions (except when converting between integers and pointers or on obscure architectures where pointer representation depends on its type). It is purely a compile-time directive which instructs the compiler to treat expression as if it had the type new-type.

Only the following conversions can be done with reinterpret_cast, except when such conversions would cast away constness or volatility.

...

5) Any object pointer type T1* can be converted to another object pointer type cv T2*. This is exactly equivalent to static_cast<cv T2*>(static_cast<cv void*>(expression)) (which implies that if T2's alignment requirement is not stricter than T1's, the value of the pointer does not change and conversion of the resulting pointer back to its original type yields the original value). In any case, the resulting pointer may only be dereferenced safely if allowed by the type aliasing rules (see below)

I thought that the reinterpret_cast guaranteed the same bit pattern, and is always compile-time statement . But in the above quote, there is exception on obscure architectures where pointer representation depends on its type, and the conversion of any object pointer type T1 to another object pointer type T2 is exactly equivalent to static_cast<cv T2>(static_cast<cv void*>(expr) ). for example,

int a   = 10;
void* b = static_cast<void*>(&a); // OK.
static_cast<int*>(b) = 20;        // OK. back to the original type. 

void* b2 = reinterpret_cast<void*>(&a); // char* b2 = static_cast<void*>(static_cast<void*>(&a) ); 
static_cast<int*>(b2) = 30; // also OK? because the resulting pointer is equivalent to b, so can be back to the original type. 

Is b resolved in run-time(can the bit pattern be changed)?. If so, is there difference between reinterpret_cast and static_cast when do any pointer-to-pointer conversion?.

tmal
  • 47
  • 6
  • 3
    What `reinterpret_cast` *is*, is usually always *a mistake*. The situations where `reinterpret_cast` is actually correct are few and far between. – Jesper Juhl Oct 19 '22 at 14:51
  • Also, generally speaking, (with or without casts) *pointers* are not/never compile-time constants. – Adrian Mole Oct 19 '22 at 15:13
  • 1
    i dont understand the question in the title. The quote clearly states that "reinterpret_cast expression does not compile to any CPU instructions" and that only in some rare obscure cases it does. – 463035818_is_not_an_ai Oct 19 '22 at 15:13
  • you seem to conclude that it always results in CPU instructions from the fact that it does so sometimes – 463035818_is_not_an_ai Oct 19 '22 at 15:15
  • @JesperJuhl Is ``reinterpret_cast`` not recommended for a pointer-to-pointer conversion? In [](https://stackoverflow.com/questions/573294/when-to-use-reinterpret-cast), the accepted answer give some example. In ``int* a = new int; void* b = reinterpret_cast(a);``), the ``b`` is not specified in the standard. But, in cppreference, ``reinterpret_cast(cv T1{} )`` is equivalent to ``static_cast(static_cast(cv T1{} )``. Is there any reason why ``reinterpret_cast`` is dangerous?. – tmal Oct 19 '22 at 16:34
  • @JesperJuhl Oh there is typo, I mean ``static_cast(static_cast(cv T1{} )`` – tmal Oct 19 '22 at 16:42
  • @463035818_is_not_a_number . thanks. I'll edit the title. the cppreference says that any pointer-to-pointer conversion with the reinterpret_cast results in ``static_cast(static_cast(cv T1{} )``. My question is if there is difference between ``reinterpret_cast`` and ``static_cast`` in pointer-to-pointer conversion. In stackoverflow.com/questions/573294/when-to-use-reinterpret-cast, the accepted answer says that the ``reinterpret_cast`` results in "unspecified". why?. – tmal Oct 19 '22 at 17:02
  • @tmal: `reinterpret_cast` *used* to have unspecified behavior for many conversions. The remainder were mostly trivial--null pointer of one type cast to a different type stayed a null pointer (likewise pointer to member). A few pointers (e.g., pointer to function) of one type could be cast to another, and back to the first and retain their original value (as long as the alignment requirements of the second were no stricter than the first). Most other conversions gave unspecified or implementation defined behavior. If memory serves, the big change here happened in C++ 17. – Jerry Coffin Oct 20 '22 at 02:23
  • It is potentially dangerous just because it does not require a valid conversion sequence, thus allowing all kinds of unsafe conversions without warning. This is why the universal advice is to use it only if you must *and* you are sure the cast is valid. – sigma Oct 20 '22 at 14:29

1 Answers1

2

Changes to the bit-pattern of a pointer aren't really quite a rare as implied, nor is the hardware necessarily quite a obscure as implied. The most common situation involves alignment requirements. A fair number of architectures require "natural alignment". That is, an object with a size of N bits also requires N-bit alignment (e.g., a 32-bit object requires 32-bit alignment).

For example:

// address with all the bits set in the least significant byte
char *x = (char *)0xabcdef;
long  *y = reinterpret_cast<long *>(x);
long z = *y;
std::cout << (void *)y;

On an x86 machine, y will usually contain exactly the bit pattern you requested (because x86 imposes few alignment requirements at the hardware level).

But on something like a SPARC, MIPS or Alpha, attempting to dereference a pointer to long with the three least significant bits set will generate a processor fault. That leaves the compiler with a choice: generate a pointer that can't be dereferenced, or clear some of the bits in the pointer. At least a few choose the latter. It's certainly not guaranteed. Some will leave the value as-is, so dereferencing it just produces a processor fault. But others try to make it into a legitimate pointer to a long by zeroing the three (or so) least significant bits.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • My understanding is that the reinterpret_cast is used for "unspecified behavior" because imcompatible(or unrelated) pointer type conversion's results is "implementation defined". And the cast can be changed the operand's bit pattern if the pointer type ``T1`` and `T2`` have the different representation each other(e.g. sizeof(char*)==sizeof(long*) ), but the conversion do not care of alignments( just reinterpeted to other pointer type). If so, ``alignas(alignof(double)) unsigned char buf[sizeof(double)]; double* p = reinterpret_cast(buf);`` is always OK? – tmal Oct 20 '22 at 04:22
  • There is typo;;. ``e.g. sizeof(char*) != sizeof(int*)`` is correct. – tmal Oct 20 '22 at 04:31
  • @tmal: in theory, your cast sequence could cause a problem (or, at least, dereferencing the resulting pointer could). It wouldn't really be related to the pointers involved though. But the bits in that array could (for example) be a signaling NaN (SNaN), in which case trying to read the data via the pointer you created could halt the processor, or something on that order. – Jerry Coffin Oct 20 '22 at 04:57
  • Then, ``alignas(alignof(double)) unsigned char buf[sizeof(double) ]; /* the buf is satisfied with the alignment requirement of double */ new(buf) double(); /* the double's lifetime begins */ *reinterpret_cast(buf) = 3.141592; /* OK? Hmm.. maybe violate strict-aliasing rule? */`` is fine?( [cppreference/new/Placement new](https://en.cppreference.com/w/cpp/language/new#:~:text=since%20C%2B%2B20)-,Placement%20new,-If%20placement%2Dparams) says that the placement new simply returns its second argument unchanged..). – tmal Oct 20 '22 at 09:42
  • @tmal: I think this is safe from strict aliasing problems--character types get "special dispensation", so if one of the types involved is (plain, signed, or unsigned) `char`, it doesn't violate strict aliasing rules. So yeah, I think the code has defined behavior. – Jerry Coffin Oct 20 '22 at 14:46