c - 具有可变长度保留空间的固定长度结构

标签 c struct

在嵌入式世界中,我们经常有通过固定长度缓冲区传递的数据结构。使用像这样的东西相对容易处理:

#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);

也就是说,我们使用数据结构作为覆盖层,以便轻松访问当前正在使用的缓冲区部分。

但是,我们有许多缓冲区格式,它们也使用缓冲区的最后 几个字节来存储诸如校验和之类的内容。我们目前使用这样的结构:

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 定义的中间,因此该类型尚未完成。

是否有一种更清洁、更易于维护的方法来执行此类操作?我基本上需要一个固定长度的结构,在开头和结尾都有字段,中间的剩余空间保留/未使用。

最佳答案

在你的情况下,我想我可能会这样做:

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 .

请注意,这可以非常有效地处理任意大的尾部结构,只要头部和尾部都适合整体尺寸即可。

关于c - 具有可变长度保留空间的固定长度结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11588442/

相关文章:

c - 使用 qsort() 对数组进行排序

c - 另一个 typedef 结构中的 typedef 结构格式

c - 二维数组和枚举

C 相当于 c++ cin.peek()

c - 嵌入式软件 : Exception occurs when calling function inside a task

c++通过共享指针为结构成员赋值导致SIGSEGV

c - 如何声明一个带有链表的结构体变量?

c - 删除空终止双向链表中的所有节点

c - 在 C 中操作值

scala - 如何向结构列添加新字段?