在嵌入式世界中,我们经常有通过固定长度缓冲区传递的数据结构。这些使用类似的东西相对容易处理:
#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);
也就是说,我们使用数据结构作为叠加层,以便轻松访问当前正在使用的缓冲区部分。
然而,我们有许多缓冲区格式,它们也使用缓冲区的 last 几个字节来存储校验和等内容。我们目前使用这样的结构:
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;
};
虽然看起来很难看这个简单的数据结构,但当结构增长到几十个字段时,这是一个绝对的怪异。它也是可维护性的噩梦,因为添加或删除结构字段意味着必须同时更新reserved
的大小计算。
当结构的末尾只包含一个项目(如校验和)时,我们有时会使用辅助函数来读取/写入值。这使数据结构保持清洁和可维护,但当缓冲区末尾有多个字段时,它不能很好地扩展。
如果我们可以做这样的事情,那将会有很大的帮助:
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;
};
不幸的是,offsetof
仅适用于完整的对象类型,因为它位于struct overlay
定义的中间,所以该类型尚未完成。
是否有更清洁,更易于维护的方法来做这类事情?我基本上需要一个固定长度的结构,在开头和结尾都有字段,中间的剩余空间保留/未使用。
答案 0 :(得分:4)
在你的情况下,我想我可能会这样做:
typedef struct overlay_head
{
uint16_t field1;
uint16_t field2;
uint8_t array1[ARY1_LEN];
} overlay_head;
typedef struct overlay_tail
{
uint32_t crc;
} overlay_tail;
enum { OVERLAY_RSVD = TOTAL_BUFFER_LENGTH - sizeof(overlay_head)
- sizeof(overlay_tail) };
typedef struct overlay
{
overlay_head h;
uint8_t reserved[OVERLAY_RSVD];
overlay_tail t;
} overlay;
您可以像以前一样工作,除了您曾经写过的地方p->field1
你现在写p->h.field1
,以及你曾经写过p->crc
的地方,你现在写p->t.crc
。
请注意,这可以非常有效地处理任意大的尾部结构,只要头部和尾部都适合整体尺寸。
答案 1 :(得分:1)
您可以定义一个结构,该结构只包含最后带有CRC字段的缓冲区:
struct checked_buffer {
char data[TOTAL_BUFFER_LENGTH - sizeof(uint32_t)];
uint32_t crc;
};
然后将“覆盖”放在data
字段上。你可能已经在构建指针,将原始缓冲区char*
“转换”为overlay*
,因此从overlay*
转换为checked_buffer*
并不是一件大事。当你想访问CRC字段时。
但是如果你想让一个字段在一堆结构中处于一致的位置,那么将它放在每个结构的开头会更容易。这样你可以直接在每个结构中声明它而不需要做任何奇怪的事情,并且你不需要任何指针强制转换来访问它。
答案 2 :(得分:0)
那怎么样?
union a256
{
struct
{
int field_a;
int field_b;
char name[16];
//
int crcshadow;
};
struct
{
char buff[256-sizeof(int)];
int crc;
};
} ;
static_assert(offsetof(a256, crcshadow) < offsetof(a256, crc), "data too big");
第一个结构包含数据,第二个结构定义此联合的固定大小。