44

Say I want to cast A* to char* and vice-versa, we have two choices (I mean, many of us think we've two choices, because both seems to work! Hence the confusion!):

struct A
{
    int age;
    char name[128];
};

A a;
char *buffer = static_cast<char*>(static_cast<void*>(&a)); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2

Both work fine.

//convert back
A *pA = static_cast<A*>(static_cast<void*>(buffer)); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2

Even this works fine!

So why do we have reinterpret_cast in C++ when two chained static_cast can do its job?

Some of you might think this topic is a duplicate of the previous topics such as listed at the bottom of this post, but it's not. Those topics discuss only theoretically, but none of them gives even a single example demonstrating why reintepret_cast is really needed, and two static_cast would surely fail. I agree, one static_cast would fail. But how about two?

If the syntax of two chained static_cast looks cumbersome, then we can write a function template to make it more programmer-friendly:

template<class To, class From>
To any_cast(From v)
{
    return static_cast<To>(static_cast<void*>(v));
}

And then we can use this, as:

char *buffer = any_cast<char*>(&a); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2

//convert back
A *pA = any_cast<A*>(buffer); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2

Also, see this situation where any_cast can be useful: Proper casting for fstream read and write member functions.

So my question basically is,

  • Why do we have reinterpret_cast in C++?
  • Please show me even a single example where two chained static_cast would surely fail to do the same job?

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    Emmm... I need a pointer of type `T*` with address 8 (for this trick http://stackoverflow.com/questions/5014061/whats-the-use-of-atl-packing-constant-when-computing-distance-from-the-start-of) - how do I do that with a `static_cast`? – sharptooth Feb 17 '11 at 06:44
  • @sharptooth: I didn't really understand that. Please post an answer explaining and demonstrating two chained `static_cast` would fail to do the job of `reinterpret_cast`. – Nawaz Feb 17 '11 at 06:47
  • 2
    @Nawaz - I don't like you're "cast-style" template function `any_cast`, because it's name is misleadingly. It will do a good job if you're casting from type `pointer-to-A` to `pointer-to-B`, but not in general ("any" cases). – 0xbadf00d Jul 07 '11 at 08:05

7 Answers7

36

There are things that reinterpret_cast can do that no sequence of static_casts can do (all from C++03 5.2.10):

  • A pointer can be explicitly converted to any integral type large enough to hold it.

  • A value of integral type or enumeration type can be explicitly converted to a pointer.

  • A pointer to a function can be explicitly converted to a pointer to a function of a different type.

  • An rvalue of type "pointer to member of X of type T1" can be explicitly converted to an rvalue of type "pointer to member of Y of type T2" if T1 and T2 are both function types or both object types.

Also, from C++03 9.2/17:

  • A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • @James: please write a small code to demonstrate what you're saying. I seriously need to understand this. :-) – Nawaz Feb 17 '11 at 06:53
  • 3
    @Nawaz: `int i = 42; char* p;` Now `p = static_cast(static_cast(i));` will fail compilation for all possible values of `X` and `Y` (unless they are class types that provide conversion functions). – j_random_hacker Feb 17 '11 at 07:08
  • 6
    also, as fifth bullet point, pointer to first element of POD struct can be converted to pointer to the struct, and vice versa. – Cheers and hth. - Alf Feb 17 '11 at 07:09
  • @Alf: Can't that be done via `static_cast(static_cast(p))` where `p` is a pointer to the struct-type object and `M` is the type of the initial member? – James McNellis Feb 17 '11 at 07:10
  • @All: Nice comments, and nice answer. I'm learning new things. Please post more :D – Nawaz Feb 17 '11 at 07:11
  • 1
    @Nawaz: I think the first two are straightforward; in any case, @sharptooth's answer gives an example of the second case and the first is just the reverse of that. I can't think of compelling examples for the latter two: it's easy to construct examples for them, but I don't know about real, useful examples. These items just form "a list of things that `reinterpret_cast` can do but no sequence of `static_cast`s can do." – James McNellis Feb 17 '11 at 07:13
  • 1
    @James: AFAIK not in C++98/03. the standard explicitly guarantees the conversion for `reinterpret_cast`, though. – Cheers and hth. - Alf Feb 17 '11 at 07:14
  • @James: Do you know any book or article that explains and lists what only `reinterpret_cast` can do but a sequence of `static_cast` cannot? – Nawaz Feb 17 '11 at 07:15
  • @Alf P. Steinbach: That's interesting. Can you provide me the reference from the Standard? – Nawaz Feb 17 '11 at 07:17
  • 1
    @Nawaz: as I recall it's at the end of the classes section intro. see my old blog posting http://alfps.wordpress.com/2010/06/14/c-basics-five-lesser-known-special-cast-operations/#first_member – Cheers and hth. - Alf Feb 17 '11 at 07:18
  • 1
    @Alf: Oh, yes, at 9.2/17. That's very convenient that that language isn't included in 5.2.10 with the rest of the `reinterpret_cast` specification! :-) Thanks for the heads-up. – James McNellis Feb 17 '11 at 07:22
  • @Nawaz: No, I don't know of any article; would a hardcopy of the C++ Standard count as a book? :-) I haven't really read any C++ texts that would cover this sort of thing, though, other than the language standard itself. – James McNellis Feb 17 '11 at 07:27
  • @James: Yes. Hardcopy of C++ Standard would count as a book. Even a softcopy, for that matter. Which section(s) from it, explains these? – Nawaz Feb 17 '11 at 07:31
  • 1
    @Nawaz: In the answer I reference 5.2.10, which defines the behavior of `reinterpret_cast`, and 9.2/17, which (as @Alf so helpfully pointed out) defines more behavior for `reinterpret_cast`. All four of the cast operators are defined in 5.2 and the C-style cast and its special powers are covered in 5.4. – James McNellis Feb 17 '11 at 07:35
16

You need reinterpret_cast to get a pointer with a hardcoded address (like here):

int* pointer = reinterpret_cast<int*>( 0x1234 );

you might want to have such code to get to some memory-mapped device input-output port.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • And that cannot be done with chained static_cast? Anyone tried that? – Nawaz Feb 17 '11 at 06:49
  • @nawaz: I don't know how to do that with `static_cast` and I've never seen anyone doing that - either C-style cast or `reinterpret_cast` is used. – sharptooth Feb 17 '11 at 06:51
  • @sharptooth: I mean, using `any_cast` (as defined in my question)? Would it fail? – Nawaz Feb 17 '11 at 06:52
  • @Nawaz: What's `any_cast`? You can use either `reinterpret_cast` or C-style cast here. – sharptooth Feb 17 '11 at 06:57
  • @sharptooth: Looks like you didn't understand the point of the question. – Nawaz Feb 17 '11 at 06:58
  • 5
    @Nawaz: This perfectly answers your question. Your any_cast does not work in this case. You cannot static_cast an int to a void*: "error: invalid static_cast from type 'int' to type 'void*'" – Brent Bradburn Feb 17 '11 at 08:43
  • @nobar: Yes, I tested that. static_cast doesn't work here. :-) – Nawaz Feb 17 '11 at 08:44
6

A concrete example:

char a[4] = "Hi\n";
char* p = &a;

f(reinterpret_cast<char (&)[4]>(p));  // call f after restoring full type
      // ^-- any_cast<> can't do this...

// e.g. given...
template <typename T, int N>   // <=--- can match this function
void f(T (&)[N]) { std::cout << "array size " << N << '\n'; }
Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
6

Other than the practical reasons that others have given where there is a difference in what they can do it's a good thing to have because its doing a different job.

static_cast is saying please convert data of type X to Y. reinterpret_cast is saying please interpret the data in X as a Y.

It may well be that the underlying operations are the same, and that either would work in many cases. But there is a conceptual difference between saying please convert X into a Y, and saying "yes I know this data is declared as a X but please use it as if it was really a Y".

jcoder
  • 29,554
  • 19
  • 87
  • 130
  • 1
    This sentence *"static_cast is saying please convert data of type X to Y. reinterpret_cast is saying please interpret the data in X as a Y."* does not help understanding, as it begs another question : what is the difference between "convert" and "interpret" in this context? – Nawaz Feb 17 '11 at 08:40
  • Conversion implies a programmed conversion, such as converting a float value to an integer . "interpret" means "I know I said this is a pointer to a int but actually it's not that it's a pointer to a float so please treat it as such" – jcoder Feb 17 '11 at 09:18
  • So what? How exactly it makes any difference as fas as understanding the difference is concerned? We're know learning english here. One can say *"I know this is `int` but interpret this as float"* when he cast using static_cast. Does it help? – Nawaz Feb 17 '11 at 09:38
  • 2
    +1 - that's conceptually key, although there are workarounds e.g. given `int x` you can `reinterpret_cast(x)`, can *not* `static_cast(x)`, but can chain ala `*static_cast(static_cast(&x))` (notice any_cast isn't a clean substitute: you need an extra deref). Crucially, `static_cast(x)` does something very different: rounding as the value is converted from `int`. – Tony Delroy Feb 17 '11 at 09:46
3

As far as I can tell your choice 1 (two chained static_cast) is dreaded undefined behaviour. Static cast only guarantees that casting pointer to void * and then back to original pointer works in a way that the resulting pointer from these to conversions still points to the original object. All other conversions are UB. For pointers to objects (instances of the user defined classes) static_cast may alter the pointer value.

For the reinterpret_cast - it only alters the type of the pointer and as far as I know - it never touches the pointer value.

So technically speaking the two choices are not equivalent.

EDIT: For the reference, static_cast is described in section 5.2.9 of current C++0x draft (sorry, don't have C++03 standard, the draft I consider current is n3225.pdf). It describes all allowed conversions, and I guess anything not specifically listed = UB. So it can blow you PC if it chooses to do so.

Tomek
  • 4,554
  • 1
  • 19
  • 19
  • undefined behaviour in what case? It depends on the datatypes also! – Nawaz Feb 17 '11 at 09:40
  • 4
    Standard guarantees that type * p and type * q = static_cast(static_cast(p)) point to the same object. Now doing static_cast(static_cast(p)) where type2 if different to type is UB (although it USUALLY works). If you try chain of static casts with inheritance (especially multiple one) you WILL see a difference. – Tomek Feb 17 '11 at 09:44
  • 1
    This is a great point! If a class uses multiple inheritance, a static-cast to a base type pointer doesn't only change the type -- it will (in some cases) also change the value. So static_cast is fundamentally different than reinterpret_cast in this example. However, the way @Nawaz is doing it (going first to void*), his "any_cast" probably still works for this. – Brent Bradburn Feb 17 '11 at 16:50
  • 1
    static_cast and reinterpret_cast both suffer from the SAME potential for undefined behavior when casting from a void* to a pointer of another type. So again, "any_cast" works fine as a replacement for reinterpret_cast for this scenario. – Brent Bradburn Feb 17 '11 at 17:13
  • "_it never touches the pointer value._" That's the intent, but the standard committee forgot to write it down. The intent is also that 2 static = 1 reinterpret. The committee also forgot. – curiousguy Dec 12 '11 at 00:27
0

Using of C Style casting is not safer. It never checks for different types can be mixed together. C++ casts helps you to make sure the type casts are done as per related objects (based on the cast you use). This is the more recommended way to use casts than using the traditional C Style casts that's always harmful.

Edwin
  • 1
-1

Look, people, you don't really need reinterpret_cast, static_cast, or even the other two C++ styles casts (dynamic* and const).

Using a C style cast is both shorter and allows you to do everything the four C++-style cast let you do.

anyType someVar = (anyOtherType)otherVar;

So why use the C++-style casts? Readability. Secondly: because the more restrictive casts allow more code safety.

*okay, you might need dynamic

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55
  • 9
    C-style cast cannot do the job of `dynamic_cast`! – Nawaz Feb 17 '11 at 07:06
  • This isn't about dynamic_cast though. Its about c, static and reinterpret. Besides, dynamic relies on RTTI. – Alexander Rafferty Feb 17 '11 at 07:16
  • 1
    You've written *" you don't really need reinterpret_cast, static_cast, or even the other two C++ styles casts (**dynamic** and const)."* – Nawaz Feb 17 '11 at 07:22
  • and -1 for advocating, in addition to simply not using recommended idioms of the language, obscuring the programmer's intentions and the possibly resulting nightmarish debugging processes – underscore_d Dec 14 '15 at 11:30