Casting
Reinterpret Cast
This cast is a binary cast. That means that the conversion is
at the bit level. Suppose we have a float type number. That number
is represented in a certain format. If we try to "reinterpret_cast"
on it then it will be a problem because the "int" format is different.
So the cmpiler does not allow it.
The reinterpret_cast is a dangerous cast as it can convert between
unrelated types due to casting at the bit level. In many cases the
compiler will not allow the cast. There can be some scenarios where
it might be useful such as: "accessing raw memory", "converting a type
data to an array of bytes for serialization",
File: reinterpret1.cpp
#include <iostream>
using namespace std ;
int main()
{
int x1 = 10;
float f1 = 10.5 ;
x1 = reinterpret_cast<int>(f1);
cout << x1 << endl ;
}
$ rm a.exe ; g++ reinterpret1.cpp ; ./a.exe
rm: cannot remove 'a.exe': No such file or directory
reinterpret1.cpp: In function ‘int main()’:
reinterpret1.cpp:11:11: error: invalid cast from type ‘float’ to type ‘int’
11 | x1 = reinterpret_cast(f1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
bash: ./a.exe: No such file or directory
Output:
$ rm a.exe ; g++ reinterpret1.cpp ; ./a.exe
reinterpret1.cpp: In function ‘int main()’:
reinterpret1.cpp:11:11: error: invalid cast from type ‘float’ to type ‘int’
11 | x1 = reinterpret_cast(f1);
The "reinterpret_cast" can only perform
pointer-to-pointer conversions and reference-to-reference
conversions (plus pointer-to-integer and integer-to-pointer
conversions). If the above cast from float to int was allowed then
the reinterpret cast will take the binary representation of the
floating number and try to create an integer out of it; resulting in
a gibberish value. It will not take the actual floating point value
and discard the fraction part because it is jsut working at a
binary level.
File: reinterpret2.cpp
#include <iostream>
using namespace std ;
int main()
{
int x1 = 10;
float f1 = 10.5 ;
//x1 = reinterpret_cast<int>(f1);
x1 = *reinterpret_cast<double*>( &f1 );
cout << x1 << endl ;
x1 = (int)f1 ;
cout << x1 << endl ;
x1 = static_cast<int>( f1 );
cout << x1 << endl ;
//pointer to pointer conversions
int x2 = 15 ;
int* p1 = &x2 ;
char* c1 = reinterpret_cast<char*>(p1) ;
cout << (int)(*c1) << endl ;
//pointer to integer conversion
long x3 = reinterpret_cast<long>(p1) ;
cout << x3 << endl ;
}
Output:
$ rm a.exe ; g++ reinterpret2.cpp ; ./a.exe
-2147483648
10
10
15
34359725064
x1 = *reinterpret_cast( &f1 );
cout << x1 << endl ;
Here we are trying to trick the compiler by doing a cast
on the pointers and getting a value out for "x1" but
we see that the value is not correct. The right way to do it
is using the "C" style cast or the "C++" style cast.
x1 = (int)f1 ;
cout << x1 << endl ;
x1 = static_cast( f1 );
cout << x1 << endl ;
The compiler will obtain the floating point value and then
discard the fraction part and store the integral value in x1.
//pointer to pointer conversions
int x2 = 15 ;
int* p1 = &x2 ;
char* c1 = reinterpret_cast(p1) ;
cout << (int)(*c1) << endl ;
//pointer to integer conversion
long x3 = reinterpret_cast(p1) ;
cout << x3 << endl ;
The above snippet shows how we can cast between an integer pointer
and a character pointer and also casting a pointer to an integral
value.
File: reinterpret3.cpp
#include <iostream>
#include <cstdint>
using namespace std;
// Hash function for pointers using reinterpret_cast
template <typename T>
struct PointerHash {
size_t operator()(const T* pointer) const {
uintptr_t addr = reinterpret_cast<uintptr_t>(pointer);
// Ensure the address fits within size_t
#if SIZE_MAX < UINTPTR_MAX
addr %= SIZE_MAX;
#endif
return addr;
}
};
int main() {
int x = 10;
int* ptr = &x;
PointerHash<int> hash_func;
size_t hash_value = hash_func(ptr);
cout << "Hash value: " << hash_value << endl;
return 0;
}
Output:
$ rm a.exe ; g++ reinterpret3.cpp ; ./a.exe
Hash value: 34359725084
The above shows how we can use "reinterpret_cast" in a
hashing function. The "uintptr_t" type is a unsigned integer type.
that can store a data pointer.