In the embedded world, we often have data structures that are passed through fixed-length buffers. They are relatively easy to use, using something like this:
#define TOTAL_BUFFER_LENGTH 4096 struct overlay { uint16_t field1; uint16_t field2; uint8_t array1[ARY1_LEN]; }; static_assert(sizeof(struct overlay) <= TOTAL_BUFFER_LENGTH); struct overlay* overlay = malloc(TOTAL_BUFFER_LENGTH);
That is, we use the data structure as an overlay to provide easy access to that part of the buffer used.
However, we do have several buffer formats that also use the last few bytes of the buffer to store things like checksums. Currently we use such designs:
struct overlay { uint16_t field1; uint16_t field2; uint8_t array1[ARY1_LEN]; char reserved[TOTAL_BUFFER_LENGTH - sizeof(uint16_t) - sizeof(uint16_t) - (sizeof(uint8_t) * ARY1_LEN) - sizeof(uint32_t)]; uint32_t crc; };
How ugly, as it searches for this simple data structure, it is an absolute monster when the structure grows to have dozens of fields. This is also a nightmare for repairability, since adding or removing a structure field means that the size calculation for reserved must be updated at the same time.
When the end of the structure contains only one element (for example, a checksum), we sometimes use a helper function to read / write the value. This makes the data structure clean and maintained, but it does not scale well when the end of the buffer has multiple fields.
This would help a lot if we could do something like this:
struct overlay { uint16_t field1; uint16_t field2; uint8_t array1[ARY1_LEN]; char reserved[TOTAL_BUFFER_LENGTH - offsetof(struct overlay, reserved) - sizeof(uint32_t)]; uint32_t crc; };
Unfortunately, offsetof only works with full object types, and since it is in the middle of a struct overlay definition, this type is not yet complete.
Is there a cleaner, more convenient way to do this? I essentially need a fixed-length structure with margins at the beginning and at the end, and the remaining space in the middle is reserved / not used.