c++filefile-handlingreinterpret-cast

Why the reinterpret_cast operator is considered dangerous in cpp? is there a better approach?


I was studying Random access in files in cpp. I came across reinterpret_cast operator. It allows you to cast a pointer from one type to another type, even if those types are not related in any way. However, it is stated that it is considered dangerous and may produce unexpected results and program crashes. I wanted to understand why and how.

The code I have written:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
    fstream file("example.txt", ios::out);
    if (!file)
    {
        cerr << "Failed to open file." << endl;
        return 1;
    }
    file.seekp(4 * sizeof(int), ios::beg);
    int newValue = 50;
    file.write(reinterpret_cast<const char *>(&newValue), sizeof(int));
    file.close();
    return 0;
}

Solution

  • the data type of a pointer defines the meaning of the bits it is pointing to. For example, unsigned integers just use binary encoding, i.e, a unsigned 4-bit int 1010 would be interpreted as a decimal 10. However, if you were to change the pointer type to signed, the bits are read in Two's Complement and interpreted as a decimal -6. Floating point types again have a totally different bit representation (i.e. the IEEE 754 standard. In other words: The pointer type defines how the bits are interpreted.

    reinterpret_cast only changes the pointer type, but not the stored bits. This means, that any semantics given by the previous data type are lost after conversion, and the interpreted values before and after the cast may vastly differ from each other. You should only use this cast when you are aware of the bit representation of your data and need to manipulate it.

    This may cause trouble not only concerning the semantics, but also the memory, as it allows you to cast to wider data types.

    uint32_t A[1] = {1};
    uint64_t* B = reinterpret_cast<uint64_t*>(A);
    

    This is a typical example of abusing memory with reinterpret_cast. You can easily get a pointer to the same memory address that A points to, but B expects 64 instead of 32 bits per element. Hence, dereferencing B has the same effect as reading from A[1]: You are trying to access memory, that was not part of the original data.