11

According to C++ Standard, a reinterpret_cast of a pointer T* to some other type pointer Q* can change or not change the pointer value depending on implementation.

I'm very interested - it there any real example of a C++ implementation where casting a pointer to some other pointer type with reinterpret_cast changes the pointer? What and why is changed there?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • you mean, "changes the value" the pointer points to? – akira Jul 21 '10 at 11:40
  • @akira: no, changes the value of the pointer itself – sharptooth Jul 21 '10 at 11:42
  • you mean like: `T* t = 0x13; Q* q = 0x42; t = reintrepret_cast(q);` yields `t != 0x42`? – akira Jul 21 '10 at 12:05
  • @akire: I guess, yes. I'm not sure myself, that's why I'm asking. You might be interested in reading the answers to the linked question - they inspired me to ask this question. – sharptooth Jul 21 '10 at 12:25
  • so you are not sure about what you are asking? :) i think the deleted answers were a result of the slightly unclear question. yes, the linked question is interesting. – akira Jul 21 '10 at 12:45

5 Answers5

7

Note that when the standard states that it can or cannot possibly do something, it does not mean that there is any current implementation that has that behavior, only that they could.

The closest that I can think of is an architecture where type alignment was required by the hardware, and an implementation that decided to correct alignment if needed. Something like:

aligned8 var;
aligned1 *p = reinterpret_cast<aligned1*>(&var);
aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8
aligned8 *a = reinterpret_cast<aligned8*>(q); // [1]

There could be a requirement that for a to be a valid pointer it has to address a memory position multiple of 8, while the argument q with lesser alignment requirements could point to any memory address.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
1

The most likely source of trouble is on a vector machine where scalar operations are defined in terms of vectors, and a scalar pointer consists of a pointer to vector with an index into the vector. Historically the original Cray architecture was like this and it caused headaches. Nowadays you might see something like that on a GPU, but I can't point something specific off the top of my head.

The most likely effect is truncation as the destination pointer type lacks bits to specify the index part. C++11 gives a nod in this direction by allowing any pointer types to be reinterpret_casted as long as they have same alignment requirements. The bits "zeroed" by stringent alignment are allowed to not exist.

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
1

I don't think the question is meaningfully different for C++ versus C pointer casts. From this answer I quote only one of the examples:

The Eclipse MV series from Data General has three architecturally supported pointer formats (word, byte, and bit pointers), two of which are used by C compilers: byte pointers for char* and void*, and word pointers for everything else

That suggests a reinterpret_cast<Word_Aligned_Type*>(char*) could lose its sense of which character/byte in the word was being pointed at, making the operation irreversible.

Community
  • 1
  • 1
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
1
class A1 { int a1; };
class A2 { int a2; };

class B: public A1, public A2 { };

#define DBG(val)  cout << #val << ": " << val << endl

// test code
B b;
DBG(&b);                                           // prints 0x42

void *p_blank = &b;
DBG(p_blank);                                      // prints 0x42
A2 *p_a2 = &b; 
DBG(p_a2);                                         // prints 0x46
void *p_reinterpreted = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted);                              // prints 0x42
A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted2);                             // prints 0x42

A2 *p_a2 = &b means give me the pointer to an A2 object within the B object. reinterpret_cast<A2*>(&b) means give me the pointer to b and treat it as an A2 pointer. The result of this reinterpret_cast has the type 'pointer to A2', therefore it produces no warning when assigned to a void* variable (or to a A2* variable).

nusi
  • 1,016
  • 9
  • 12
  • 6
    In your example the `reinterpret_cast` does not change the value at all... you're off I am afraid. – Matthieu M. Jul 21 '10 at 13:14
  • In `A2 *p_a2 = &b;` you use implicit conversion that is equivalent to `static_cast`, not `reinterpret_cast`. – sharptooth Jul 21 '10 at 13:17
  • It seems I didn't understand the question correctly. I understood that you search for a case where reinterpret_cast<> returns a different value than a blank 'address of' operator. I didn't find a clause in the C++ standard which allows that reinterpret_cast differs from reinterpret_cast. – nusi Jul 21 '10 at 13:37
  • @akira: When you make an implicit upcast (or `static_cast`) to a base pointer, the returned pointer is the address of that base's subclass within the object. When you do that with the first base, the addresses coincide. If there is multiple inheritance, upcasting to all but the first base (assuming that the first base class is not empty) will produce pointers that are offset. In this particular example, `A1` class takes exactly 4 bytes. – David Rodríguez - dribeas Jul 21 '10 at 13:37
0

Reinterpret_cast will never return a different address - it is required to copy the exact address.

In cases of multiple inheritance, like David Rodriguez said, taking the address of one of the bases may return an address that has an offset to the address of the first base. Reinterpret_cast will return that offset address, but if you treat it as the upcast address, hell will ensue.

For upcasting, static_cast can return an different address than the one given. If the address you have is one of the bases, and that address is being at an offset to the first base address, static_cast will return a valid address for the upcasted object, which is equal to the address of the first base and thus not equal to the pointer passed.

To make it short: reinterpret_cast gives you the same address, always. Static_cast and dynamic_cast may return a different address, e.g. in certain cases involving multiple inheritance.

The difference between static_cast and dynamic_cast is that static_cast does not check whether the pointer you give it is the right object for the cast, so be sure of that before calling it.

Alex
  • 17
  • 2
  • 1
    A statement involving "required" should be backed up with a source. All I see is that you're allowed to convert to a pointer of less-strictly aligned type *and then back*, and "The result of any other such pointer conversion is unspecified." (5.2.10/7) – Potatoswatter Nov 09 '12 at 04:44
  • 1
    Um, I missed alignment issues completely, I can see how that would change the address. Thanks for the correction. – Alex Nov 09 '12 at 05:12