是否应该使用宏而不是灵活的数组成员?

Should one be using macros instead of flexible array members?

让我们假设如下:

我想为 UDP packets 创建一个结构。每个帧通常由一个以太网报头、一个 IP 报头、一个 UDP 报头和一个可选的有效载荷组成,最后是 FCS(帧校验和序列)。
有效负载长度为 unknown/flexible。 这意味着在创建结构时,有效负载必须是它的最后一个成员 (flexible array member)。因此,FCS 没有立足之地。

所以我想了想还有什么可能。

我想出了以下代码:

#define UDP_PKT(name, payload_length) struct __attribute((__packed__))      \
    {                                                                       \
        struct ether_header eth;                                            \
        struct ip iph;                                                      \
        struct udphdr udph;                                                 \
        unsigned char payload[payload_length];                              \
        u_int32_t fcs;                                                      \
    } name;

因为这是不允许的:

struct __attribute__((__packed__)) udp_packet
{
    struct ether_header eth;
    struct ip iph;
    struct udphdr udph;
    unsigned char payload[]; // fam, must always be the last member
    u_int32_t fcs;
};

我的问题:这是我必须在结构中包含 FCS 而没有固定数组(有效负载)大小的唯一可能性吗?

如果是这样,这是一个好的解决方案吗?这被认为是好的做法吗?

具有灵活数组成员的 struct 的大小是在运行时确定的,因此您的第一种方法也行不通。解决方案是在您准备好为线路序列化您的 struct 时将 FCS 放在缓冲区的末尾:

struct __attribute__((__packed__)) udp_packet {
    struct ether_header eth;
    struct ip iph;
    struct udphdr udph;
    u_int32_t fcs;
    unsigned char payload[]; // Move fcs up
};

void serialize_udp_packet(const udp_packet* p) {
    // Compute buffer size, and allocate the buffer
    // Place the header into the buffer
    // Copy the payload into the buffer
    // Place FCS into the buffer at the end
}

您甚至可以从 udp_packet 中完全排除 fcs,并且仅在序列化 struct 时才计算它。这种方法的一个优点是您可以自由地改变有效载荷,而不必一直将 FCS 同步到更改后的有效载荷。

为有效负载和校验和分配内存。使用指针访问校验和。简单高效