Reputation: 1149
This seems like something that should be simple and straightforward, but Google turns up very little.
What’s a clean, modern (C++11) way of initializing a simple file header struct like the following
typedef struct FooHeader {
uint8_t FooCount;
uint8_t BarCount;
uint32_t BazOffsets[4];
} FooHeader;
with the data contained in a std::vector<unsigned char>
? Is it a good idea to create a sub vector and cast its data to the header struct type, or?
Upvotes: 2
Views: 316
Reputation: 40603
To avoid running into packing, alignment and endianness issues, it is best to read the data at the byte level (on almost all modern hardware, you can assume 8-bit bytes, but packing often changes between compilers (or even just between different compilation flags) and both big and little endian computers are still common).
This means that your best bet is something like:
FooHeader load_FooHeader(std::vector<unsigned char> const &dat) {
static_assert(
std::numeric_limits<unsigned char>::digits == 8,
"Assumes 8-bit bytes");
FooHeader retv;
retv.FooCount = dat[0];
retv.BarCount = dat[1];
//Start at the fifth byte, to allow for padding.
//If you want to use a packed format, use index = 2;
std::size_t index{4};
for (std::size_t i{0}, iend{4}; i < iend; ++i) {
retv.BarOffsets[i] = 0;
//Adjust ordering depending on desired endianness.
//Currently uses little endian.
for (std::size_t j{0}, jend{4}; j < jend; ++j) {
retv.BarOffsets[i] |= dat[index + i*4 + (3-j)] << (j*8);
}
}
return retv;
}
Upvotes: 3