static_cast VS reinterpret_cast when casting pointers to pointers
Asked Answered
C

1

4

Given the following conditions:

struct A
{
    int a;
};

struct B
{
    int b;
};

int main()
{
    A  a {1};
    A* p = &a;

Does casting with static_cast and with reinterpret_cast via void* give the same result? I.e is there any difference between the following expressions?

    static_cast      <A*> ( static_cast      <void*> (p) );
    reinterpret_cast <A*> ( reinterpret_cast <void*> (p) );

What if we cast pointer to one class to pointer to another class with static_cast and with reinterpret_cast? Is there any difference between these two operators? Are the following expressions the same?

    static_cast      <B*> ( static_cast      <void*> (p) );
    reinterpret_cast <B*> ( reinterpret_cast <void*> (p) );
    reinterpret_cast <B*> (                           p  );

Can I use B* pointer after this to access b member?

Counterblow answered 25/6, 2021 at 21:35 Comment(0)
V
7

is there any difference between the following expressions?

static_cast      <A*> ( static_cast      <void*> (p) );
reinterpret_cast <A*> ( reinterpret_cast <void*> (p) );

No.

Are the following expressions the same?

static_cast      <B*> ( static_cast      <void*> (p) );
reinterpret_cast <B*> ( reinterpret_cast <void*> (p) );
reinterpret_cast <B*> (                           p  );

Yes.

Easy way to understand this is to think about how reinterpret_cast from pointer to pointer is specified. reinterpret_cast<T*>(ptr) is specified to behave exactly the same as static_cast<T*>(static_cast<void*>(ptr)) (I've left out cv qualifiers for simplicity).

And of course, static_cast<T>(static_cast<T>(anything)) is equivalent to static_cast<T>(anything) because the outer cast is always an identity conversion.


Can I use B* pointer after this to access b member?

No. If you did that, then the behaviour of the program would be undefined.

Vance answered 25/6, 2021 at 21:40 Comment(6)
It might be worth mentioning that the cast from p to B* is not always equivalent to casting to void* first -- it just is for OP's examples. If A and B were hierarchically related, the pointer value can change as part of the cast. Plus, casting from A -> void -> B AFAIK is always undefined behavior to dereference, whereas A -> B can be legal provided two types are layout-compatibleBrachio
I think it is worth mentioning the standard on this for completeness: "8.5.1.10 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 cv T”, the result is static_cast<cv T*>(static_cast<cv void*>(v))."Hypersensitive
@Brachio A and B were hierarchically related, the pointer value can change as part of the cast. In case of static_cast<A*>(b_ptr), yes. If there wasn't inheritance, that cast would be ill-formed. Plus, casting from A -> void -> B AFAIK is always undefined behavior to dereference, whereas A -> B can be legal provided two types are layout-compatible If you mean reinterpret_cast and those casts are pointers, then those two are identical in every regard and the access is UB regardless of layout compatibility. If you mean static_cast then latter may be well defined.Vance
@Brachio Regarding If A and B were hierarchically related, the pointer value can change as part of the cast technically, the pointer value can change in most casts casts to another type (even other than hierarchical static or dynamic cast) because the pointer types aren't generally required to have the same representation except in particular cases. All pointers typically do have the same representation in practice though like for example on 64 bit x86.Vance
@Vance Given struct Coordinate{double x, double y, double z}; double *ptr1, *ptr2; Coordinate stSpaceCoord; Any difference between ptr1 = static_cast<void*>(&stSpaceCoord); and ptr2 = reinterpret_cast<void*>(&stSpaceCoord); ? Thanks.Stichometry
@Stichometry No, there's never a difference between static and reinterpret cast to (or from) void*.Vance

© 2022 - 2024 — McMap. All rights reserved.