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

7 c arrays struct sizeof flexible-array-member

我想在其中声明一个带有灵活数组成员的结构,然后使用sizeof()它.原型是:

typedef struct
{
    uint16_t    length;
    uint8_t     array[][2];
} FLEXIBLE_t;
Run Code Online (Sandbox Code Playgroud)

然后我宣布它:

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

一切编译好的(GCC),但是当我审视test.length它的值是2,也就是说,它只是计数uint16_tlength本身.

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

hac*_*cks 11

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

C11-§6.7.2.2/ 18

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

请注意,标准C不允许在代码中初始化灵活的阵列成员.它将调用未定义的行为(参见§6.7.2.2第20和21段).GCC允许将此作为扩展:

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


Jen*_*edt 5

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

...特别是,结构的大小就好像省略了柔性阵列构件,除了它可能具有比遗漏意味着更多的尾随填充.

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


小智 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);
Run Code Online (Sandbox Code Playgroud)