0

Suppose i have two structs

struct B 
{ 
int n;
};

struct C
{ 
int k;
};

and

B b = {};
C& c = reinterpret_cast<C&>(b); //Not Ok , compiler(gcc 8.5 with -O2 -Wall) is not happy 
C *c1 = reinterpret_cast<C*>(&b); //Okay, compiler(gcc 8.5 with -O2 -Wall) is happy

sample code:

#include<new>
#include<iostream>



int main() {


struct B { int n; };


struct C
 { int k; }
;

B b = {};
C c = reinterpret_cast<C&>(b);
C *c1 = reinterpret_cast<C*>(&b);

printf("b.n is %d\n",b.n);
printf("c.k is %d\n",c.k);
printf("c1.k is %d\n",c1->k);
    return 0;
}

Can somebody help me to understand why there is difference in behavior for above code though I believe they are functionally same?

I expected compiler to be happy even on references as I know both types have same memory alignment.

I get the following warning

<source>:142:29: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
 C c = reinterpret_cast<C&>(b);

see https://godbolt.org/z/4o7bhGrYP

Haridas
  • 3
  • 3
  • 2
    [I can't replicate any ***errors***](https://godbolt.org/z/Wo68Esqq1), but I do get some warnings. Please create a [mre], and [edit] your question to show it together with the actual error message (copy-paste the full and complete build log as text). – Some programmer dude Apr 14 '23 at 13:39
  • 2
    As for the warning, please [read about strict aliasing](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule). – Some programmer dude Apr 14 '23 at 13:41
  • 4
    `reinterpret_cast` is a signal to the compiler that says "trust me, I know what I'm doing, leave me alone". Any warnings/errors you get out of incorrect usage is just a bonus. – NathanOliver Apr 14 '23 at 13:43
  • 1
    in your godbolt link there is no error, its a warning – 463035818_is_not_an_ai Apr 14 '23 at 13:44
  • 1
    not sure what your aim is, but `c1` does not point to a `C`. You may cast `c1` back to a pointer to `B` but thats about all you can do with `c1`. If you want to convert a `B` to a `C` you need a proper conversion – 463035818_is_not_an_ai Apr 14 '23 at 13:48

1 Answers1

4

The bullet for reinterpret_cast that applies here is:

  1. 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)

and

  1. An lvalue (until C++11) glvalue (since C++11) expression of type T1 can be converted to reference to another type T2. The result is that of *reinterpret_cast<T2*>(p), where p is a pointer of type “pointer to T1” to the object designated by expression. No temporary is created, no copy is made, no constructors or conversion functions are called. The resulting reference can only be accessed safely if allowed by the type aliasing rules (see below)

The type aliasing rule says

Whenever an attempt is made to read or modify the stored value of an object of type DynamicType through a glvalue of type AliasedType, the behavior is undefined unless one of the following is true:

The only bullet that might apply is:

  • AliasedType and DynamicType are similar.

And similar is one of the following:

  • they are the same type; or
  • they are both pointers, and the pointed-to types are similar; or
  • they are both pointers to member of the same class, and the types of the pointed-to members are similar; or
  • they are both arrays of the same size or both arrays of unknown bound, and the array element types are similar. (until C++20)
  • they are both arrays of the same size or at least one of them is array of unknown bound, and the array element types are similar.

A and C are not arrays. A* and C* are not similar.

Ergo, both c and c1 are pretty useless. c cannot be accessed and c1 can only be cast back to a A*. Anything else results in undefined behavior.

The compiler is not mandated to warn or error on undefined behavior. It warns for the reference because there is nothing you can do with the reference. It does not warn for the pointer, because such cast can be useful (but only as intermediate result, only to cast back to B*).

reinterpret_cast is not a any-to-any cast that you can apply just because A and C look the same. If you want to convert a B to a C you need a proper conversion.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185