Should I Use Static_Cast or Reinterpret_Cast When Casting a Void* to Whatever

Is it Legal to reinterpret_cast to a void*

It is always legal to convert from a pointer to a type to a pointer to a different type including void, so if T is a type this is legal C++:

T* x;
void *y = reinterpret_cast<void *>(x);

In real world it is never used because void * is a special case, and you obtain the same value with static_cast:

void *y = static_cast<void *>(x); // equivalent to previous reinterpret_cast

(in fact above conversion is implicit and can be simply written void *y = x; - thank to Michael Kenzel for noticing it)

To be more explicit the standard even says in draft n4659 for C++17 8.2.10 Reinterpret cast [expr.reinterpret.cast], §7

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)).

When you refer to byte and char being the only legal types, it is just that it is legal to dereference the converted pointer only for those types. void is not included here because you can never dereference a void *.


To specifically answer your question

.. I'm casting from an int** to a void*. And I will eventually cast from the void* back to an int**.

The standard guarantees that first one is a standard (read implicit) conversion:

A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer
to cv void”. The pointer value (6.9.2) is unchanged by this conversion.

So this is always legal:

int **i = ...;
void *v = i;

For back casting, standard says (in static_cast paragraph):

A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T”,

So this is also legal

int **j = static_cast<int **>(v);

and the standard ensures that j == i.

static_cast VS reinterpret_cast when casting pointers to pointers

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.

When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn't necessary, but it's important to note that the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.


const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.

const_cast also works similarly on volatile, though that's less common.


dynamic_cast is exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards – you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.


reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another — such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type). There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of a pointer to aligned data.


C-style cast and function-style cast are casts using (type)object or type(object), respectively, and are functionally equivalent. They are defined as the first of the following which succeeds:

  • const_cast
  • static_cast (though ignoring access restrictions)
  • static_cast (see above), then const_cast
  • reinterpret_cast
  • reinterpret_cast, then const_cast

It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then, consider the longer, more explicit option.

C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.

Which cast to use; static_cast or reinterpret_cast?

static_cast provided that you know (by design of your program) that the thing pointed to really is an int.

static_cast is designed to reverse any implicit conversion. You converted to void* implicitly, therefore you can (and should) convert back with static_cast if you know that you really are just reversing an earlier conversion.

With that assumption, nothing is being reinterpreted - void is an incomplete type, meaning that it has no values, so at no point are you interpreting either a stored int value "as void" or a stored "void value" as int. void* is just an ugly way of saying, "I don't know the type, but I'm going to pass the pointer on to someone else who does".

reinterpret_cast if you've omitted details that mean you might actually be reading memory using a type other than the type is was written with, and be aware that your code will have limited portability.

By the way, there are not very many good reasons for using a void* pointer in this way in C++. C-style callback interfaces can often be replaced with either a template function (for anything that resembles the standard function qsort) or a virtual interface (for anything that resembles a registered listener). If your C++ code is using some C API then of course you don't have much choice.

Why can I use static_cast With void* but not With char*

Your question really has 2 parts:

  1. Should I use static_cast or reinterpret_cast to work with a pointer to the underlying bit pattern of an object without concern for the object type?
  2. If I should use reinterpret_cast is a void* or a char* preferable to address this underlying bit pattern?

static_cast: Converts between types using a combination of implicit and user-defined conversions

In 5.2.9[expr.static.cast]13 the standard, in fact, gives the example:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));

It leverages the implicit cast:

A prvalue pointer to any (optionally cv-qualified) object type T can be converted to a prvalue pointer to (identically cv-qualified) void. The resulting pointer represents the same location in memory as the original pointer value. If the original pointer is a null pointer value, the result is a null pointer value of the destination type.*

There is however no implicit cast from a pointer of type T to a char*. So the only way to accomplish that cast is with a reinterpret_cast.

reinterpret_cast: Converts between types by reinterpreting the underlying bit pattern

So in answer to part 1 of your question when you cast to a void* or a char* you are looking to work with the underlying bit pattern, reinterpret_cast should be used because it's use denotes to the reader a conversion to/from the underlying bit pattern.

Next let's compare void* to char*. The decision between these two may be a bit more application dependent. If you are going to use a standard library function with your underlying bit pattern just use the type that function accepts:

  • void* is used in the mem functions provided in the cstring library
  • read and write use char* as inputs

It's notable that C++ specific libraries prefer char* for pointing to memory.
Holding onto memory as a void* seems to have been preserved for compatibility reasons as pointer out here. So if a cstring library function won't be used on your underlying bit patern, use the C++ specific libraries behavior to answer part 2 of your question: Prefer char* to void*.

casting via void* instead of using reinterpret_cast

For types for which such cast is permitted (e.g. if T1 is a POD-type and T2 is unsigned char), the approach with static_cast is well-defined by the Standard.

On the other hand, reinterpret_cast is entirely implementation-defined - the only guarantee that you get for it is that you can cast a pointer type to any other pointer type and then back, and you'll get the original value; and also, you can cast a pointer type to an integral type large enough to hold a pointer value (which varies depending on implementation, and needs not exist at all), and then cast it back, and you'll get the original value.

To be more specific, I'll just quote the relevant parts of the Standard, highlighting important parts:

5.2.10[expr.reinterpret.cast]:

The mapping performed by reinterpret_cast is implementation-defined. [Note: it might, or might not, produce a representation different from the original value.] ... A pointer to an object can be explicitly converted to a pointer to an object of different type.) Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value, the result of such a pointer conversion is unspecified.

So something like this:

struct pod_t { int x; };
pod_t pod;
char* p = reinterpret_cast<char*>(&pod);
memset(p, 0, sizeof pod);

is effectively unspecified.

Explaining why static_cast works is a bit more tricky. Here's the above code rewritten to use static_cast which I believe is guaranteed to always work as intended by the Standard:

struct pod_t { int x; };
pod_t pod;
char* p = static_cast<char*>(static_cast<void*>(&pod));
memset(p, 0, sizeof pod);

Again, let me quote the sections of the Standard that, together, lead me to conclude that the above should be portable:

3.9[basic.types]:

For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value.

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T).

3.9.2[basic.compound]:

Objects of cv-qualified (3.9.3) or cv-unqualified type void* (pointer to void), can be used to point to objects of unknown type. A void* shall be able to hold any object pointer. A cv-qualified or cv-unqualified (3.9.3) void* shall have the same representation and alignment requirements as a cv-qualified or cv-unqualified char*.

3.10[basic.lval]:

If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined):

  • ...
  • a char or unsigned char type.

4.10[conv.ptr]:

An rvalue of type “pointer to cv T,” where T is an object type, can be converted to an rvalue of type “pointer to cv void.” The result of converting a “pointer to cv T” to a “pointer to cv void” points to the start of the storage location where the object of type T resides, as if the object is a most derived object (1.8) of type T (that is, not a base class subobject).

5.2.9[expr.static.cast]:

The inverse of any standard conversion sequence (clause 4), other than the lvalue-to-rvalue (4.1), array-topointer (4.2), function-to-pointer (4.3), and boolean (4.12) conversions, can be performed explicitly using static_cast.

[EDIT] On the other hand, we have this gem:

9.2[class.mem]/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. [Note: There might therefore be unnamed padding within a POD-struct object, but not at its beginning, as necessary to achieve appropriate alignment. ]

which seems to imply that reinterpret_cast between pointers somehow implies "same address". Go figure.

Which one to use when static_cast and reinterpret_cast have the same effect?

Everybody has noted that reinterpret_cast<> is more dangerous than static_cast<>.

This is because reinterpret_cast<> ignores all type information and just assigns a new type without any real processing, as a result the processing done is implementation defined (though usually the bit patterns of the pointers are the same).

The thing everybody fails to mention is that reinterpret_cast<> is a means to document your program. It tells somebody reading the code that we had to compromise something and as a result we have ended up with a dangerous cast, and be careful when you mess with this code.

Use the reinterpret_cast<> to highlight these dangerous areas in the code.

When casting from a void* there is not type information for the cast to work with.

So you are either doing an invalid cast or a casting back to the original type that was previously cast into a void*. Any other type of casting is going to end up with some undefined behavior.

This is the perfect situation to use reinterpret_cast<> as the standard guarantees that casting a pointer to void* and back to its original type using reinterpret_cast<> will work. And by using reinterpret_cast<> you are pointing out to the humans that come along afterwords that something bad is happening here.

should I use it or static_castvoid* then static_castmyType* to avoid reinterpret_cast?

§5.2.10 describes the legal mappings that reinterpret_cast can perform, and specifies that “No other conversion can be performed”.

The conversion relevant for your example is /7:

A pointer to an object can be explicitly converted to a pointer to a different object type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types … and the alignment requirements of T2 are no stricter than those of T1. [emphasis mine]

The result of the conversions of any other pointer to object types is “unspecified”.1

This is one of two reasons why reinterpret_cast is dangerous: its conversion is only well-defined for a subset of pointer to object types, and compilers usually offer no diagnostics about accidental misuse.

The second reason is that the compiler doesn’t even check whether the mapping you are trying to perform is legal in the first place, and which of the many (semantically completely different) mappings is going to be performed.

Better to be explicit and tell the compiler (and the reader) which the intended conversion is that you want to perform. That said, asdf’s comment isn’t quite correct, because not all conversions that you might want to perform via reinterpret_cast are equivalent to using static_cast<void*> followed by a static_cast to the target type.


1 Aside: In a nutshell (and slightly simplified), a “standard layout type” is a type (or array of type) which doesn’t have virtual functions or mixed member visibility, and all its members and bases are also standard layout. The alignment of a type is a restriction on the addresses in memory at which it may be located. For example, many machines require that doubles are aligned at addresses divisible by 8.



Related Topics



Leave a reply



Submit