如何定义一个具有未知大小成员的结构?

问题描述 投票:0回答:1

我在 PLDM Base 规范 MultipartReceive 响应中定义了一个遵循表 17 的结构。该结构用于从其他组件接收数据。按照规范,我们无法知道数据的大小,并且在它下面有另一个 uint32_t crc 校验和。那么我该如何定义这个响应结构呢?

Multipart接收响应

我决定像下面这样定义它,CRC校验和将成为数据[]的一部分。

typedef struct {
    uint8_t completion_code;        // completion code
    uint8_t transfer_flag;
    uint32_t next_transfer_handle;
    uint32_t data_length_bytes;
    uint8_t data[];
} __attribute__((packed)) MultipartReceiveResp_T;

但是我的队友说为了安全起见我应该像下面这样定义这个结构:

typedef struct {
    uint8_t completion_code;        // completion code
    uint8_t transfer_flag;
    uint32_t next_transfer_handle;
    uint32_t data_length_bytes;
    uint8_t data[1];
} __attribute__((packed)) MultipartReceiveResp_T;

哪个选项更好?为什么?我很困惑为什么我们必须为此定义单个数组。 谢谢你们

c
1个回答
0
投票

哪个选项更好?为什么?

uint8_t data[];
更好,因为它正确地 没有为没有固定大小的数组指定大小。
uint8_t data[1];
更糟糕,因为它错误地告诉编译器数组只有一个元素,而通常情况并非如此。

对于其大小将在运行时确定的数组成员,将数组定义为具有一个元素或零个元素是旧版本 C 中使用的一种拼凑。C 标准已更改为提供一种定义灵活数组成员的方法,使用

[]
语法。这种新方法应该比拼凑方法更受青睐。

除其他效果外,如果您将数组定义为具有一个元素,然后使用

MyStructure.data[i]
进行访问,编译器会推断
i
的值必须为零,这是符合行为的,因为这是定义的唯一值用于访问定义为具有一个元素的数组。所以,如果你有一个循环,例如:

for (int i = 0; i < n; ++i)
{
    …
    t[i] = MyStructure.data[i];
}

编译器可以将其优化为:

if (n)
{
    …
    t[0] = MyStructure.data[0];
}

从而消除循环的所有迭代,其中

i
将为 1、2、3 或更多。一般来说,当你对编译器撒谎时,可能会发生不好的事情。

至于你应该做什么,这看起来像是从某些通信设备读入缓冲区的数据。将缓冲区正确解释为

MultipartReceiveResp_T
结构的方法取决于具体情况。如果缓冲区是动态分配的,那么通过网络读取例程将字节复制到其中,可能会满足 C 标准在缓冲区中有效创建结构对象的要求,并且您可以安全地使用结构类型为缓冲区添加别名。但是,如果缓冲区被定义为
char
的静态数组,则在没有编译器保证的情况下,这种别名将不安全。如需进一步指导,您必须展示更多涉及的代码。

至于访问

data
中的数据后的校验和,则需要计算地址,然后再根据情况确定正确的访问方法。

© www.soinside.com 2019 - 2024. All rights reserved.