在使用灵活数组的结构初始化中使用sizeof运算符

时间:2017-01-29 16:23:13

标签: c arrays struct sizeof flexible-array-member

我想在其中声明一个包含灵活数组成员的结构,然后在其上使用sizeof()。原型是:

typedef struct
{
    uint16_t    length;
    uint8_t     array[][2];
} FLEXIBLE_t;
然后我宣布:

const FLEXIBLE_t test = {
    .length = sizeof(test),
    .array = {  {   0,  1   },
                {   2,  3   },
                {   4,  5   },
                {   6,  7   },
                {   8,  9   } }
};

所有内容都可以编译(GCC),但是当我检查test.length时,它的值为2,即它只计算uint16_t本身的length

如何在编译时计算结构的大小?编译器似乎使用的是原型而不是特定的实例。

4 个答案:

答案 0 :(得分:11)

sizeof忽略灵活的数组成员,因为灵活的数组成员在结构中不占用空间。

C11-§6.7.2.2/ 18

  

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这被称为灵活的阵列成员。 在大多数情况下,会忽略灵活的数组成员。特别地,结构的大小就好像省略了柔性阵列构件,除了它可能具有比遗漏意味着更多的尾随填充。 [...]

请注意,标准C不允许在代码中初始化灵活的数组成员。它将调用未定义的行为(参见§6.7.2.2第20和21段)。虽然GCC允许这是extension

  

GCC允许灵活数组成员的静态初始化。这相当于定义一个包含原始结构的新结构,后跟一个足够大小的数组来包含数据。

答案 1 :(得分:5)

灵活的数组成员不计算大小:

  

...特别是,结构的大小就像是灵活的   数组成员被省略,除了它可能有更多的尾随   填补比遗漏意味着。

除了大小问题之外,您的代码在C中具有未定义的行为。无法像这样初始化灵活的数组成员。从这个意义上说,Gcc可能有一个扩展,但这不是便携式的。

答案 2 :(得分:2)

GCC允许将灵活数组初始化为扩展名:https://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/Zero-Length.html

但是,sizeof()遵循C标准,并认为结构中的灵活数组的大小为零。在任何情况下,当尝试在结构的初始值设定项中使用sizeof()时,结构在该阶段是不完整的,并且最终大小尚未知晓。只知道具有零长度柔性阵列的原型的大小。

大小在编译时是已知的,但是直到结构初始化之后才知道。 GCC的if ((isset($_SERVER['HTTPS']) && (($_SERVER['HTTPS'] == 'on') || ($_SERVER['HTTPS'] == '1'))) || (isset($_SERVER['HTTPS']) && $_SERVER['SERVER_PORT'] == 443)) { 将在此实例中计算为数字常量,但必须从函数调用,因为它不总是常量,因此不能在初始化程序中使用。

因此必须在运行时分配__builtin_object_size(),但至少分配的值会编译为常量:

.length

答案 3 :(得分:1)

sizeof()运算符返回的大小(差不多)忽略了灵活数组。

根据C Standard, 6.7.2.1 Structure and union specifiers, paragraph 18

  

作为一种特殊情况,结构的最后一个元素有多个   命名成员可能具有不完整的数组类型;这叫做a   灵活的阵列成员。在大多数情况下,灵活的阵列   成员被忽略。 特别是结构的大小   好像灵活的阵列成员被省略除外   它可能比遗漏意味着更多的尾随填充。