7

我想声明一个带有灵活数组成员的结构,然后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

4 回答 4

12

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

C11-§6.7.2.2/18

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。[...]

请注意,标准 C 不允许像在您的代码中那样进行灵活的数组成员初始化。它将调用未定义的行为(参见 §6.7.2.2 第 20 和 21 段)。虽然 GCC 允许将此作为​​扩展

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

于 2017-01-29T16:27:28.923 回答
5

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

...特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。

除了大小问题之外,您的代码在 C 中还有未定义的行为。不能像那样初始化灵活的数组成员。Gcc 在这个意义上可能有一个扩展,但这不是可移植的。

于 2017-01-29T16:31:20.807 回答
2

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

但是,sizeof() 遵循 C 标准,并认为结构中的灵活数组的大小为零。在任何情况下,当尝试在结构的初始化程序中使用 sizeof() 时,该结构在该阶段是不完整的,并且最终大小尚不清楚。只有原型的大小及其零长度的灵活数组是已知的。

然而,大小在编译时是已知的,只是在结构初始化之后才知道。在这种情况下, GCC__builtin_object_size()将评估为数字常量,但必须从函数调用,因为它并不总是常量,因此不能在初始化程序中使用。

所以.length必须在运行时赋值,但至少被赋值的值编译为一个常量:

test.length = __builtin_object_size(test, 0);
于 2017-01-29T16:42:03.457 回答
1

sizeof()运算符返回的大小(几乎)忽略了灵活数组。

根据C 标准,6.7.2.1 结构和联合说明符,第 18 段

作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活数组成员。在大多数情况下,灵活数组成员被忽略。 特别是,结构的大小就像省略了柔性数组成员一样, 只是它可能具有比省略所暗示的更多的尾随填充。

于 2017-01-29T16:30:55.980 回答