在结构中使用结构的一个成员变量分配数组的长度是否有效?

时间:2017-11-19 23:38:20

标签: c

我正在尝试在结构体内创建一个数组,如下所示:

struct __attribute__((__packed__)) INIT_HEADER
{
    uint16_t rounter_n;
    uint16_t update_interval;
    uint16_t router_IDs[rounter_n];
    ...
    ...   
}

这实际上是在一个字符串上强制转换,我将从中逐个提取每个字段。该字符串将具有许多router_ID(和其他详细信息)作为路由器的数量。

基本上,第一个32位是非重复的。其余的是重复的,并且重复次数与路由器的数量一样多。请参阅下图。

Image

我希望能够创建一个可以有效地在此字符串上强制转换的结构,具体取决于路由器的数量。

2 个答案:

答案 0 :(得分:2)

VLA无效作为结构的一部分。 GCC有一个扩展(如果你想搜索它和周围的争议,称为VLAIS),但据我所知它只对在函数内部用块作用域声明的结构类型有效,并且大小为不是取自struct成员,而是取自struct进入范围时计算的某个表达式(例如,基于函数中的局部变量)。

在任何情况下,您采取的方法都不是便携式的,也不是好的风格。 clang / LLVM没有(并且不会,因为可以说是非常好的理由,他们拒绝支持VLAIS,并且"打包"结构不是便携式的,无论如何都有很多陷阱。从样式/最佳实践的角度来看,您应该编写正确的序列化/反序列化函数来处理数据流,而不是尝试将外部数据视为C类型。

答案 1 :(得分:1)

无法使用可变长度数组创建struct。否则,struct的不同实例可能具有不同的大小,这是不允许的。有一个称为灵活数组成员的构造是允许的,但仅适用于struct中的最后一个字段。

从数据格式的角度来看,您尝试设置的方式无论如何都是不正确的。您有一系列路由器ID,但该图显示了路由器ID后跟两个端口的组,成本和IP地址。通过此设置,您实际上可以使用灵活的阵列成员,如下所示:

struct __attribute__((__packed__)) router {
    uint16_t ID;
    uint16_t port1;
    uint16_t port2;
    uint16_t cost;
    uint32_t IP_addr;
};

struct __attribute__((__packed__)) INIT_HEADER {
    uint16_t rounter_n;
    uint16_t update_interval;
    struct router routers[];
};

然后,您可以使用无符号字节数组并将其强制转换为指向此结构的指针。

请注意,假设通过网络接收此数据结构,您很可能需要在每个ntohs和{{{{}}上调用ntohluint16_t 1}}字段分别为了提取正确的值。

此外,正如其他答案中所提到的那样,由于uing32_t中的填充,您可能会面临结构与接收数据不完全匹配的风险。

有关结构打包的更多详细信息,请参阅this guide