Code:
char keyStr[50]={ 0x5F, 0x80 /* bla bla */ };
uint32_t* reCast = reinterpret_cast< uint32_t* >( &keyStr[29] );
uint32_t* reCast2 = ( uint32_t* )
The difference is that with C-style cast in C++ file in some cases you will get error and cannot compile. reinterpret_cast
solves such cases. Something like - you tell to compiler: "I know it is incompatible casting, but let assume it is ok". C++ is far more restricted than C for such things like casting.
In your example there are no differences between the C style cast and the reinterpret_cast, because you are casting between unrelated pointers, and there is no constness. If you have had a const
on one part, reinterpret_cast would have choked when C style cast would have done the const_cast under the hood.
The danger of the reinterpret_cast (or of the C style cast) is precisely that it allows casting between unrelated objects. In your example, you have a high risk that when you dereference reCast
(or reCast2
) you get an error because you try to access a misaligned integer.
At low level, all casting have same effect (if they are valid) : they will all give the value or address. The main difference is :
All this cast were added in C++ to avoid the catch all mode of C style cast and allow for some compile and run time checks. - a dynamic_cast will only be allowed at compile time between related types and the compiler will insert code to control validity at run time
In what way do you mean "not dangerous"? reinterpret_cast is incredibly dangerous. It tells the compiler it is safe to ignore what it thinks it knows about the value.
It's not as dangerous as a c-style cast which throws away the const/volatileness of the value in question as well as any information about what it is pointing to.
Understanding these operations in assembly language is a bit pointless. They aren't assembly language constructs. They're C++ language constructs, that work something as follows:
static_cast
- Effectively this converts an object from one type to another. Note this can change the value (static_cast<float>(1)
doesn't have the same bit pattern as 1 for instance).
dynamic_cast
- if this object can be considered to be another type through inheritance, then treat it as such, otherwise render it as zero. This won't change the value of a pointer but it does safely change the compilers view of it.
const_cast
- throw away const
(or volatile
) qualifiers, which is not often a good idea as it allows you to destroy data the client thought was safe.
reinterpret_cast
- treat the bit pattern as meaning something different to what the compiler thought it did. Usually used for pointers and hopefully rarely. reinterpret_cast
ing an int into a float
is unlikely to be a good idea, but it will keep the same bit pattern.
c-style-cast - Take the bit pattern, forget completely what you know about it, and treat it as something else. A dangerous and almost invisible combination of static_cast
, reinterpret_cast
and const_cast
. It's not considered a good idea in C++ code because it's hard to spot in a review, and because it is not specific about what is happening.
reinterpret_cast
and const_cast
are ways of getting around the C++ type system. As you noted for reinterpret_cast
, this usually translates to little or no assembly code.
static_cast
mostly respects the C++ type system. It could convert a number from one type to another, or call a constructor, or call a conversion function. Or for a derived-to-base conversion, it might involve adding byte offsets and/or lookups into a vtable. static_cast
can also bend the type system's rules by "downcasting" a pointer or reference from a non-virtual base type to a derived type, possibly subtracting a byte offset.
And then there are pointers-to-member. They're probably beside the point here, but static_cast
does things to them more or less analogous to class pointer conversions.
dynamic_cast
respects the C++ type system even more strictly. In its useful form, it checks at runtime whether or not a pointer/reference actually points/refers to an object of the specified type. It typically calls a magic library function under the covers.
A function-style cast with one argument has exactly the same effect as a C-style cast. (With more than one argument, a function-style cast must be a temporary initialization using a class constructor.) A C-style cast does the first thing that makes sense out of the following list:
const_cast
static_cast
static_cast
and then a const_cast
reinterpret_cast
, orreinterpret_cast
and then a const_cast
One exception: C-style casts can ignore private and protected inheritance relations between classes, pretending they have a public inheritance relation instead.
C-style casts are usually not preferred in C++ because it's less specific about what you want to happen.