Code:
char keyStr[50]={ 0x5F, 0x80 /* bla bla */ };
uint32_t* reCast = reinterpret_cast< uint32_t* >( &keyStr[29] );
uint32_t* reCast2 = ( uint32_t* )&keyStr[29];
if( reCast == reCast2 ){
cout << "Same Thing!";
}
Output:
Same Thing!
I wonder what's the difference between the two casting methods. Also if you could specify ( with examples ) difference between static_cast, dynamic_cast, and other types of casting you know ( i.e. while staying as low level and as close to assembly language as possible ).
static_cast
dynamic_cast
const_cast
reinterpret_cast
C-style cast (type)value
Function-style cast type(value)
Thanks.
Please read the P.S. I know from the example above that reinterpret_cast assigns to the int pointer the address of keyStr[29] In assembly that would translate into:
lea eax, [keyStr+1D]
mov [reCast], eax
So in other words reinterpret_cast, in a low level prospective, is not dangerous at all as it does not modify the original data.
I wanted to know how the other casting methods behave in a low level way. So, for example, an object, in a low level way, is just a variable which holds an address. And the type if that object is how the compiler then interprets that address and how it offsets it.( this is exactly what I'm not interested in, in assembly, i could care less if that variable holds a value, a pointer or an object ( i.e. another pointer ) ). Another thing that could be just the same, is the difference between int and int* or unsigned int and int; all 4 declarations generate the same assembly instruction. ( push value ) or (sub esp-(length of int) && mov esp, value) I hope this clarifies the question and why I tagged it "low-level-code" and "assembly"
P.S. In this program I'm trying to create I don't care for non portability or other high level stuff. I'm trying to be as low level as possible and as close to assembly language as possible. That means that, for this program, memory is just memory ( i.e. 0 and 1 bits ) and types are not important ( e.g. I don't care if mem address: 0x123 is an "int" type or "float" type, it's just "data")
reinterpret_cast
andconst_cast
are ways of getting around the C++ type system. As you noted forreinterpret_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 aconst_cast
reinterpret_cast
, orreinterpret_cast
and then aconst_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.