Is reinterpret_cast and c-style cast compatible (b

2019-08-18 03:28发布

问题:

The C++ standards mentions that reinterpret_cast is implementation defined, and doesn't give any guarantees except that casting back (using reinterpret_cast) to original type will result in original value passed to first.

C-style casting of at least some types behaves much the same way - casting back and forth results with the same value - Currently I am working with enumerations and ints, but there are some other examples as well.

While C++ standard gives those definitions for both cast-styles, does it also give the same guarantee for mixed casts? If library X returns from function int Y() some enum value, can use any of above casts, without worrying what cast was used to convert initial enum to int in Y's body? I don't have X's source code, so I cannot check (and it can change with next version anyway), and things like that are hardly mentioned in documentation.

I know that under most implementations in such cases both casts behave the same; my question is: what does C++ standard say about such cases - if anything at all.

回答1:

C++ defines the semantic of the C cast syntax in terms of static_cast, const_cast and reinterpret_cast. So you get the same guaranteed for the same operation whatever syntax you use to achieve it.



回答2:

reinterpret_cast can only be used for specific conversions:

  • Pointer to (sufficiently large) integer, and the reverse
  • Function pointer to function pointer
  • Object pointer to object pointer
  • Pointer-to-member to pointer-to-member
  • lvalue expression to reference

plus (conditionally) function pointer to object pointer and the reverse. In most cases, the converted value is unspecified, but there is a guarantee that a conversion followed by its reverse will yield the original value.

In particular, you can't use reinterpret_cast to convert between integer an enumeration types; the conversion must be done using static_cast (or implicitly, when converting an unscoped enumeration to an integer type), which is well defined for sufficiently large integer types. The only possible problem is if the library did something completely insane such as return reinterpret_cast<int&>(some_enum);

A C-style cast will perform either a static_cast or a reinterpret_cast, followed by a const_cast, as necessary; so any conversion that's well-defined by static_cast is also well-defined by a C-style cast.



回答3:

No, reinterpret_cast is not equivalent to a C style cast. C style casts allow casting away const-volatile (so it includes the functionality of const_cast) not allowed in reinterpret_cast. If static_cast is allowed between the source and destination types, it will perform a static_cast which has different semantics than reinterpret_cast. It the conversion is not allowed, it will fallback to reinterpret_cast. Finally there is a corner case where the C cast cannot be represented in terms of any of the other casts: it ignores access specifiers.

Some examples that illustrate differences:

class b0 { int a; };
class b1 { int b; };
class b2 { int c; };
class d : public b0, public b1, b2 {};
int main() {
   d x;
   assert( static_cast<b1*>(&x) == (b1*)&x );
   assert( reinterpret_cast<b1*>(&x) != (b1*)&x ); // Different value
   assert( reinterpret_cast<b2*>(&x) != (b2*)&x ); // Different value, 
                                                   // cannot be done with static_cast
   const d *p = &x;
   // reinterpret_cast<b0*>(p);                    // Error cannot cast const away
   (b0*)p;                                         // C style can
}