I'm writing some code that uses the fstream read() function and this function expects a char* as the buffer. Later on, I want to work with the bytes in this buffer as unsigned chars, so I'm either going to have to: 1. declare the buffer as a char* and then do static_casts for each element later, 2. declare the buffer as unsigned char* and then do a reinterpret_cast when I pass it to the read function, or 3. declare the buffer as a char* and also create a casted pointer that I use for accessing the buffer as an unsigned char.
Here's a snippet:
char* buf = new char[512];
unsigned char* ubuf = reinterpret_cast<unsigned char*>(buf);
fstream myfile;
myfile.open("foo.img");
myfile.seekg(446);
myfile.read(buf, 16);
//myfile.read(reinterpret_cast<char*>(buf), 16);
int bytes_per_sector = ubuf[1] << 8 | ubuf[0];
...
I like this way because I only have to cast once and I can just access the buffer as either type without doing a cast every time. But, Is this a good practice? Is there anything that can go wrong here? Using reinterpret_cast makes me a little nervous because I don't normally use it and I've been told to be careful with it so many times.
In this case a reinterpret_cast is fine, for 2 reasons:
The (signed) char
and unsigned char
types are required to have the same "representation and alignment". This means that there is not going to be a difference in the data (it will be bit-per bit exact), or how long the buffer is interpreted to be.
File reading functions typically use char*
just as a generic data-access type. They can't use void*
because the type void
has an specifically undefined length and representation. char
, however, does. So they can use it to read/write a series of bytes.
Actually, file-functions are oftentimes intended to have data be reinterpreted as/from something else. It allows you to have a struct like
typedef struct structSomeStruct
{
char name[8]; // a basic, fixed length, string
unsigned long i; // a 32 bit value
float x, y, z, w;
} SomeStruct;
Or
class SomeStruct
{
public:
char name[8];
unsigned long i;
float x, y, z, w;
SomeStruct()
{
// ...
}
};
And store it to a file using something like:
SomeStruct st;
// populate the st data structure
// file.write(char* start_of_data, size_t number_of_bytes);
file.write(reinterpret_cast<char*>(&st), sizeof(SomeStruct));
And read it similarly.