257

Both static_cast and reinterpret_cast seem to work fine for casting void* to another pointer type. Is there a good reason to favor one over the other?

Dev Null
  • 4,731
  • 1
  • 30
  • 46
Andy
  • 3,004
  • 2
  • 22
  • 12

9 Answers9

206

Use static_cast: it is the narrowest cast that exactly describes what conversion is made here.

There’s a misconception that using reinterpret_cast would be a better match because it means “completely ignore type safety and just cast from A to B”.

However, this doesn’t actually describe the effect of a reinterpret_cast. Rather, reinterpret_cast has a number of meanings, for all of which holds that “the mapping performed by reinterpret_cast is implementation-defined.” [5.2.10.3]

But in the particular case of casting from void* to T* the mapping is completely well-defined by the standard; namely, to assign a type to a typeless pointer without changing its address.

This is a reason to prefer static_cast.

Additionally, and arguably more important, is the fact that every use of reinterpret_cast is downright dangerous because it converts anything to anything else really (for pointers), while static_cast is much more restrictive, thus providing a better level of protection. This has already saved me from bugs where I accidentally tried to coerce one pointer type into another.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
68

The static_cast is more appropriate for converting a void* to a pointer of some other type.

static_cast is the cast of choice when there is a natural, intuitive conversion between two types that isn't necessarily guaranteed to work at runtime. For example, you can use static_cast to convert base class pointers to derived class pointers, which is a conversion that makes sense in some cases but can't be verified until runtime. Similarly, you can use static_cast to convert from an int to a char, which is well-defined but may cause a loss of precision when executed.

reinterpret_cast, on the other hand, is a casting operator designed to do conversions that are fundamentally not safe or not portable. For example, you can use reinterpret_cast to convert from a void * to an int, which will work correctly if your system happens to have sizeof (void*)sizeof (int). You can also use reinterpret_cast to convert a float* to an int* or vice-versa, which is platform-specific because the particular representations of floats and ints aren't guaranteed to have anything in common with one another.

In short, if you ever find yourself doing a conversion in which the cast is logically meaningful but might not necessarily succeed at runtime, avoid reinterpret_cast. static_cast is a good choice if you have some advance knowledge that the cast is going to work at runtime, and communicates to the compiler "I know that this might not work, but at least it makes sense and I have a reason to believe it will correctly do the right thing at runtime." The compiler can then check that the cast is between related types, reporting a compile-time error if this isn't the case. Using reinterpret_cast to do this with pointer conversions completely bypasses the compile-time safety check.

There are a few circumstances where you might want to use a dynamic_cast instead of a static_cast, but these mostly involve casts in a class hierarchy and (only rarely) directly concern void*.

As for which one is preferred by the spec, neither is overly mentioned as "the right one to use" (or at least, I don't remember one of them being mentioned this way.) However, I think the spec wants you to use static_cast over reinterpret_cast. For example, when using a C-style cast, as in

A* ptr = (A*) myVoidPointer;

The order of casting operators that's tried always tries to use a static_cast before a reinterpret_cast, which is the behavior you want since reinterpret_cast isn't guaranteed to be portable.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 2
    To clarify: what the author means here by "`static_cast`... isn't necessarily guaranteed to work at runtime" is, "Your program may crash later on." If you `static_cast` from a base type to a derived type, it **will** "work" at runtime (i.e. you will **not** get an exception or a `NULL` pointer), but the result may be pointing to the wrong memory location if multiple inheritance is involved. (See [this answer](http://stackoverflow.com/a/7789468/266704) for more details.) Only `dynamic_cast` will do a runtime check (using RTTI) and fail gracefully if the cast is invalid. – andrewtc Aug 09 '14 at 22:51
12

This is a tough question. On the one hand, Konrad makes an excellent point about the spec definition for reinterpret_cast, although in practice it probably does the same thing. On the other hand, if you're casting between pointer types (as is fairly common when indexing in memory via a char*, for example), static_cast will generate a compiler error and you'll be forced to use reinterpret_cast anyway.

In practice I use reinterpret_cast because it's more descriptive of the intent of the cast operation. You could certainly make a case for a different operator to designate pointer reinterprets only (which guaranteed the same address returned), but there isn't one in the standard.

Nick
  • 6,808
  • 1
  • 22
  • 34
  • 8
    "_different operator to designate pointer reinterprets only (which guaranteed the same address returned)_" Hug? That operator **is** `reinterpret_cast`! – curiousguy Dec 19 '11 at 06:18
  • 4
    @curiousguy Not true according to the standard. reinterpret_cast does NOT guarantee that the same address is used. Only that if you reinterpret_cast from one type to another *and then back again*, you will get back the same address you started with. – ClydeTheGhost Mar 01 '19 at 20:58
3

You likely obtained that void* with implicit conversion, so you should use static_cast because it is closest to the implicit conversion.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
2

Casting to and from void* using static_cast and using reinterpret_cast is identical. See the answer at the link. But usually static_cast is preferred because it is more narrow and in general (but not in this specific case) more safe conversion.

anton_rh
  • 8,226
  • 7
  • 45
  • 73
2

There's confusion about implementation defined mappings. That is about mappings. The implementation can internally map however it likes, but it must make other guarantees otherwise. A result of reinterpret_cast can't simply arbitrarily point to what the implementation would otherwise consider some other object's location -- though the outward representation may differ. (Though converting to integer and back will have original value, in specific circumstances, outlined). Fundamentally, it's irrelevant whether the implementation's reinterpreted cast returns the same "memory location"; whatever it returns is mapped to the same "value". (Incidentally, The core guidelines explicitly answer a case where using reinterpret_cast (char*/unsigned char*/std::byte*) to view raw object representation is defined behavior.)

Relevant standards rules the void* cast:

static_cast:

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”, where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. If the original pointer value represents the address A of a byte in memory and A does not satisfy the alignment requirement of T, then the resulting pointer value is unspecified. Otherwise, if the original pointer value points to an object a, and there is an object b of type T (ignoring cv-qualification) that is pointer-interconvertible (6.8.3) with a, the result is a pointer to b. Otherwise, the pointer value is unchanged by the conversion. [Example 3 : T* p1 = new T; const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); bool b = p1 == p2; // b will have the value true. —end example]

reintrepret_cast:

An object pointer can be explicitly converted to an object pointer of a different type.68 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))

The key is the last sentence. For the purposes of this question's void* cast, (and assuming object types meet alignment requirements, cv qualifications, and are safefly-derived pointers):

reinterpret_cast T* from void* is equivalent to static_cast T* from void*.

But you should definitely, definitely absolutely definitely use static_cast for no other reason that the scary folklore about reinterpret_cast and convolutedness of the ISO standard may lead to get you needlessly harangued by peers.

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun

mysticsbun
  • 21
  • 1
0

I suggest using the weakest possible cast always.

reinterpret_cast may be used to cast a pointer to a float. The more structure-breaking the cast is, the more attention using it requires.

In case of char*, I'd use c-style cast, until we have some reinterpret_pointer_cast, because it's weaker and nothing else is sufficient.

Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69
Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
  • 3
    "_reinterpret_cast is may be used to cast a pointer to a float._" Certainly not! – curiousguy Dec 19 '11 at 06:16
  • certainly yes, curiousguy. Check the standard again. – Pavel Radzivilovsky Dec 19 '11 at 18:10
  • "_Check the standard again._" Have _you_ checked the standard? – curiousguy Dec 21 '11 at 05:49
  • Yes. Not sure what you mean by example though - the only intended use for that would be forwarding a float thru a pointer-expecting cookie. – Pavel Radzivilovsky Dec 21 '11 at 11:29
  • How do you cast a pointer to a float? `void* p = 0; float f = reinterpret_cast(p);` generates `error: invalid cast from type ‘void*’ to type ‘float’`. I can cast to int, but not float. – Oscar Korz Dec 29 '11 at 22:46
  • 4
    Probably `float f = *reinterpret_cast(&p);` – Ben Voigt Aug 07 '13 at 15:33
  • 2
    @BenVoigt That is casting between pointers; one of them happened to be a float pointer. – nodakai Jun 01 '16 at 15:46
  • @nodakai: Nope, it reinterprets the bits of `p` as a `float`. A pointer to `p` is used to accomplish this, but `p` is coerced to `float` not `float*`. – Ben Voigt Jun 01 '16 at 16:40
  • @BenVoigt: That `reinterpret_cast` is casting from some pointer (whatever `p` is) to a `const float*`. That pointer is then dereferenced to get the float value. This does result in the bit representation of `p` being used as a `float`, but the `reinterpret_cast` itself is still casting a pointer type to a different pointer type. – Cemafor Jun 15 '16 at 21:44
  • @cemafor no not from whatever p is to `float*`. From "pointer to what p is" - a double pointer. – Ben Voigt Jun 15 '16 at 22:02
  • @BenVoigt: Sorry, I meant the type the `reinterpret_cast` is casting is a pointer to whatever type `p` is. If `p` is a `double`, it would be casting from a `double*` to a `const float*`. The type of `&p` is a `double*`. – Cemafor Jun 15 '16 at 22:20
  • @BenVoigt the `*` before `reinterpret_cast` is not part of the cast. It is a deference operator replied to the result of the cast. In this code `reinterpret_cast` converts a pointer to a pointer. Then the latter pointer is dereferenced, after the cast is complete. – M.M Jul 26 '18 at 05:54
  • @M.M: I know that `*` is a separate operator, but my comment is still correct. Did you overlook the additional `&` in the operand of `reinterpret_cast`? – Ben Voigt Jul 26 '18 at 12:17
  • @BenVoigt I didn't overlook it, and your comment is wrong. `reinterpret_cast(&p)` converts a pointer to a pointer. The content of the `< >` is the result type of the cast. – M.M Jul 27 '18 at 01:45
  • Then, the unary dereference operator is applied to the result of the cast. The `*` operator converts `const float *` to `float` (the cast operator does not convert to `float`) – M.M Jul 27 '18 at 01:51
  • 1
    @M.M: The entire expression taken together, `*reinterpret_cast(&p)`, does coerce `p` to `float`. My comment is not wrong. – Ben Voigt Jul 27 '18 at 03:14
  • 8
    @BenVoigt the "entire expression" isn't a cast though. The expression consists of a dereference applied to a cast. You claimed that it was possible to cast a pointer to `float`, which is false. The expression casts `void **` to `const float *`, and then uses a dereference operation (which is NOT a cast), to convert `const float *` to `float`. – M.M Jul 27 '18 at 04:37
  • 1
    @M.M: Indeed it's not a cast. I never called it one. – Ben Voigt Jul 27 '18 at 04:41
  • 2
    @BenVoigt you offered that code in response to someone asking "How do I cast...", and then when someone said that the code casts between pointers (which it does), you said "Nope" – M.M Jul 27 '18 at 04:54
  • 1
    @M.M: I presumed that the person asking may have said "cast" but wanted a conversion that wasn't a direct cast. And then another user claimed it cast a `void*` to a `float*`, which was wrong. It cast a `void**` to a `float*`, to convert a `void*` to a `float`. – Ben Voigt Jul 27 '18 at 12:02
0

Use static_cast for this. Only in the rarest of rare cases when there is no other way use reinterpret_cast.

Asha
  • 11,002
  • 6
  • 44
  • 66
-3

reinterpret_cast will forcefully convert the void* to the target data type. It doesn't guarantee any safety and your program might crash as the underlying object could be anything.

For ex, you could typecast an myclass* to void* and then use reinterpret_cast to convert it to yourclass* which may have a completely different layout.

So its better and recommended to use static_cast

mukeshkumar
  • 2,698
  • 3
  • 19
  • 20
  • 3
    static_cast will not prevent this from happening. Once a pointer has degenerated into a void* you can static_cast it to any type of pointer. – Dan O Feb 16 '11 at 07:40