reinterpret_cast and static_cast

Started by
6 comments, last by GameDev.net 18 years, 3 months ago
what are different between them? I think reinterpret_cast is used for pointer cast and for other static type ,use static_cast .
Advertisement
reinterpret_cast is more low-level, and simply changes the way the actual bits of data are interpreted. static_cast actually attempts to see if the types can be converted at compile-time, so you can't just do arbitrary conversions between completely incompatible types. Thus reinterpret_cast is pretty unsafe, the unsafest of all the casts resembling a C-style cast, while static_cast is a little more safe but still allows you to do unsafe conversions if you're not careful.
You're right that reinterpret_cast works on pointers and static_cast is more generally associated with non-pointer types (but not always. The most basic example is converting from "void *"). However, I prefer to think of them in terms of how they arrive at the end result.

Consider the code:
#include <iostream>int main() {  float f = 1.5;  int i = 0;  i = static_cast<int>(f);  std::cout << i << "\n";  i = *reinterpret_cast<int *>(&f);  std::cout << i << "\n";#if 0  i = *static_cast<int *>(&f);  std::cout << i << "\n";#endif  return 0;}


This prints (on my computer):

1
1069547520

If you change the "#if 0" to "#if 1" it fails to compile with the error (I'm using Mingw):

test.cpp: In function `int main()':
test.cpp:13: invalid static_cast from type `float*' to type `int*'

static_cast<int>(f) returns the int that is "equivalent" to f. The standard says that this conversion truncates the float to the nearest integer.

reinterpret_cast<int *>(&f) reinterprets the bits in &f (pointer to f) as a pointer to int. We then dereference this pointer, which has the effect of reinterpretting the bits of the float 1.5 as an int. These bits happen to form the same pattern as the int 1069547520.

static_cast<int *>(&f) produces an error because there's no pointer to int equivalent to a pointer to float. This makes sense, because we can't very well change what &f points to to make it look like the equivalent int.
Here is a run down of the different c++ casts. I compiled this list a year or two ago for interview preparation.


static cast
Conventional casting of one type to another, where there is some meaning to what the cast will do. (Thus, normally you can't cast from a Foo to a Bar, unless there's a definition for how to do this). Casting from one type to another is interesting, particularly, casting float to int. Like the unary minus, the casting operation does NOT change the value of the variable it is casting. Instead, like unary minus, it creates a temporary value which is the casted result.


reinterpret cast
To allow you to cast one pointer type to another pointer type to another. Since all pointers are addresses, and all addresses have the same number of bytes (at least, on a given ISA), the casting does not convert any bits. C++ decided to call this pointer-to-pointer casting, reinterpret_cast. What's being reinterpreted is the meaning of the bytes. When reinterpeting that pointer to a Bar * pointer, those bytes of the Foo object are unchanged.


dynamic cast
Meant for downcasting from a base class to a derived class. This check is done at runtime (as opposed to static casting which can generate the necessary code to do the casting at compile time). Will return NULL if unable to cast.


const cast
To temporarily add or remove constness from a const variable. Mostly used to get rid of warnings about violating constness.
Quote:Original post by helix
static_cast creates a temporary variable while reinterpret_cast actually changes the bits.

reinterpret_cast will not change the value of the object casted; there is no change in the bits, and static_cast may not create a temporary.
Ahh, you were too quick! I was just coming back to edit my post. :(
As others have noted, reinterpret_cast never changes the bits, it merely tells them to be interpreted as the new type. This can lead to bugs that static_cast avoids. Here's a couple of examples:

class B1 { char b1; };class B2 { char b2; };class C : public B1, B2 {};C * c = new C();B1 * b1a = static_cast<B1*>(c);B2 * b2a = static_cast<B2*>(c);B1 * b1b = reinterpret_cast<B1*>(c);B2 * b2b = reinterpret_cast<B2*>(c);


In this example, b1a & b2a are guaranteed to be pointers to the two base classes of the derived class. OTOH, b1b & b2b are not guaranteed to properly point to the two base classes. More importantly, b2b is guaranteed not to point to the B2 base class because it does not begin in memory at the same position as C. This is guaranteed because B1 is non-empty and is declared as a base of C before B2 is. Most compilers I know of will return the appropriate pointer for the B1 base; however, it's not guaranteed according to the spec.

The next example is interesting for two reasons: 1) it illustrates that an intial base class may not be at the start of the struct in popular compilers, and 2) this can happen in single-inheritence too.

class ScreenObj { int left, right, top, bottom; };class Drawable : public ScreenObj { virtual void Draw(); }// Given some drawable d...ScreenObj obj = reinterpret_cast<ScreenObj*>(&d);


Under VC, obj will not point to the ScreenObj in drawable. Drawable has a vtable at the front of it, but ScreenObj does not. In VC, ScreenObj is at offset 4 of Drawable, not 0. Early GCC put the vtable at the first position after all base classes; however, I don't know if that's still the case.

The moral of the story is to be very careful with using reinterpret_cast. It can really bite you in the butt in ways that might be difficult to track down.
Quote:Original post by Troll
The moral of the story is to be very careful with using reinterpret_cast. It can really bite you in the butt in ways that might be difficult to track down.


reinterpret_cast should probably be held in the same position as casts in C: It's usually an indication of poor design. Of course, there are times it's unavoidable (by which I mean the cure is worse than the disease. Perhaps, for example, when interfacing with some libraries), but it should throw up a red flag.

static_cast is less worrisome, but should still make you take a second look at your design (perhaps it should throw up a yellow flag).

This topic is closed to new replies.

Advertisement