I would like to know how best to work with on-disk data structures given that the storage layout needs to exactly match the logical design. I find that structure alignment & packing do not really help much when you need to have a certain layout for your storage.
My approach to this problem is defining the (width) of the structure using a processor directive and using the width when allocation character (byte) arrays that I will write to disk after appending data that follows the logical structure model.
eg:
typedef struct __attribute__((packed, aligned(1))) foo {
uint64_t some_stuff;
uint8_t flag;
} foo;
if I persist foo on-disk the "flag" value will come at the very end of the data. Given that I can easily use foo when reading the data using fread on a &foo type then using the struct normally without any further byte fiddling.
Instead I prefer to do this
#define foo_width sizeof(uint64_t)+sizeof(uint8_t)
uint8_t *foo = calloc(1, foo_width);
foo[0] = flag_value;
memcpy(foo+1, encode_int64(some_value), sizeof(uint64_t));
Then I just use fwrite and fread to commit and read the bytes but later unpack them in order to use the data stored in various logical fields.
I wonder which approach is best to use given I desire the layout of the on-disk storage to match the logical layout ... this was just an example ...
If anyone knows how efficient each method is with respect to decoding/unpacking bytes vs copying structure directly from it's on-disk representation please share , I personally prefer using the second approach since it gives me full control on the storage layout but I am not ready to sacrifice looks for performance since this approach requires a lot of loop logic to unpack / traverse through the bytes to various boundaries in the data.
Thanks.