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 isstatic_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), thenconst_cast
reinterpret_cast
reinterpret_cast
, thenconst_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:
- Should I use
static_cast
orreinterpret_cast
to work with a pointer to the underlying bit pattern of an object without concern for the object type? - If I should use
reinterpret_cast
is avoid*
or achar*
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 themem
functions provided in thecstring
libraryread
andwrite
usechar*
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. Avoid*
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-unqualifiedchar*
.
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 toT1
” is converted to the type “pointer to cvT2
”, the result isstatic_cast<cv T2*>(static_cast<cv void*>(v))
if bothT1
andT2
are standard-layout types … and the alignment requirements ofT2
are no stricter than those ofT1
. [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 double
s are aligned at addresses divisible by 8.
Related Topics
Difference Between an Int and a Long in C++
C++: Life Span of Temporary Arguments
Why Isn't Vector≪Bool≫ a Stl Container
Reading and Writing Binary File
What Is Meant With "Const" At End of Function Declaration
How to Implement Aba Counter With C++11 Cas
Debugging Core Files Generated on a Customer'S Box
How to Call a Parent Class Function from Derived Class Function
How to Implement Big Int in C++
Convert Python Program to C/C++ Code
C++ Std::Set Update Is Tedious: I Can't Change an Element in Place
How to Pad an Int With Leading Zeros When Using Cout ≪≪ Operator
How to Create a Dynamic Array of Integers