I have an 18 byte struct in C++. I want to read 18 bytes of data from a file straight into this struct. However, my C++ compiler pads the struct to be 20 bytes (4 byte aligned). This is relatively easy to get around for just my compiler alone but I would prefer to use a method that is more reliable cross-platform/cross-compiler.
This is the struct:
struct Test {
uint8_t a;
uint8_t b;
uint8_t c;
uint16_t d;
uint16_t e;
uint8_t f;
uint16_t g;
uint16_t h;
uint16_t i;
uint16_t j;
uint8_t k;
uint8_t l;
};
Currently I use an ifstream and read it to the struct like so:
Test test;
// file is a binary ifstream
file.read((char*)test.a, 18);
On my system this skips past the two bytes of padding at the beginning of the struct. I could add bytes to the front of the struct to guarantee it to be 32 bytes which would be a valid alignment on most systems, however I don’t know if that would actually work with how structs need their elements to be naturally aligned.
Any help on this would be great but I could always end up copying the bytes manually into the attributes 😔.
>Solution :
If you are writing for cross-platform and cross-compiler, forget the direct read. Just read byte-by-byte. If profiling indicates you need further optimization, either play with the underlying stream buffering or read into a byte array and extract each piece.
This also eliminates system endianness problems.
// extract byte values
t.a = f.get();
t.b = f.get();
...
// extract a little-endian value
t.d = f.get();
t.d = t.d | (f.get() << 8);
...
// check for success or failure
if (!f) ...
Block read via a byte array:
unsigned char buffer[ 18 ];
if (!f.read( (char *)buffer, sizeof(buffer) ))
...
t.a = buffer[0];
...
t.d = buffer[3] | (buffer[4] << 8);
...
Again, profile before deciding there is an issue.