具有灵活数组成员的结构数组如何表现?

正如标题所述,我想知道具有灵活数组成员的C结构数组如何表现。 这是一个例子:

struct vector { size_t length; double array[]; }; 

维基百科的文章说:

这种结构上的sizeof运算符需要给出灵活数组成员的偏移量。

在我的机器上,这对应于8个字节( sizeof(size_t) )。 但是,当我执行以下操作时会发生什么:

显然,数组不能保存向量v0的数据,因为它只有3 * 8字节= 24字节宽。 我该如何处理这样的情况?

 #define LENGTH 10 int main() { struct vector arr[3]; struct vector *v0 = calloc(1, sizeof(*v0) + LENGTH * sizeof(v0->array[0])); v0->length = LENGTH; size_t i; for (i = 0; i length; i++) { v0->array[i] = (double) i; } struct vector v1; struct vector v2; arr[0] = *v0; arr[1] = v1; arr[2] = v2; for (i = 0; i data[%2zu] equals %2.0lf.\n", i, v0->array[i]); } return 0; } 

例如,当我正在编写一个库(header: mylib.h ,source: my lib.c )并想要隐藏用户的一个特定结构的实现时(在头文件中声明的结构,在source-hidden中定义)。 可悲的是,这个结构包含一个灵活的数组成员。 当用户尝试创建命名结构数组时,这是否会导致意外行为?

额外 :阅读有关OpenSTD C规范中灵活arrays的更多信息。
只需搜索“ 灵活的arrays成员 ”。

编辑 :C11标准的最新草案,C语言的最新免费参考可在此处获得: http : //www.open-std.org/jtc1/sc22/wg14/www/docs/n1570。 PDF格式

具有灵活数组作为其最后成员的结构不能用作其他结构的成员或数组元素。 在这种结构中,不能使用柔性arrays,因为它具有0个元素的大小。 Jonathan Leffler引用的C标准是明确的,尽管使用的语言非常技术性,并且通过搜索灵活性在标准中找不到段落。

编译器应该为您的struct vector数组发出错误。

在你的程序中,你应该使用一个指向struct vectors的指针数组,每个指针指向一个为其灵活数组中适当数量的元素分配的对象。

这是一个修改版本:

 #include  #include  struct vector { size_t length; double array[]; }; struct vector *make_vector(size_t n) { struct vector *v = malloc(sizeof(*v) + n * sizeof(v->array[0])); v->length = n; for (size_t i = 0; i < n; i++) { v->array[i] = (double)i; } return v; } int main(void) { struct vector *arr[3]; arr[0] = make_vector(10); arr[1] = make_vector(5); arr[2] = make_vector(20); for (size_t n = 0; n < 3; n++) { for (size_t i = 0; i < arr[n]->length; i++) { printf("arr[%zu]->array[%2zu] equals %2.0lf.\n", n, i, arr[0]->array[i]); } } return 0; } 

您不能拥有具有灵活数组成员的结构数组。

C标准,ISO / IEC 9899:2011,说:

6.7.2.1结构和联合说明符

¶3结构或联合不应包含具有不完整或函数类型的成员(因此,结构不应包含其自身的实例,但可包含指向其自身实例的指针), 但结构的最后一个成员除外多个命名成员可能具有不完整的数组类型; 这样的结构(以及可能递归地包含这种结构的成员的任何联合)不应是结构的成员或数组的元素。

强调添加 – 斜体部分禁止具有灵活arrays成员的结构arrays。 但是,您可以拥有指向此类结构的指针数组,但每个结构都将单独分配。

¶18作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型; 这称为灵活的arrays成员 。 在大多数情况下,忽略灵活的数组成员。 特别地,结构的尺寸好像省略了柔性arrays构件,除了它可以具有比遗漏所暗示的更多的拖尾填充。 但是,当一个. (或-> )运算符有一个左操作数,它是一个带有灵活数组成员的结构(指针),右操作数命名该成员,它的行为就好像该成员被最长的数组替换(具有相同的元素类型) )不会使结构大于被访问的对象; 数组的偏移量应保持为灵活数组成员的偏移量,即使这与替换数组的偏移量不同。 如果此数组没有元素,则其行为就好像它有一个元素,但如果任何尝试访问该元素或生成一个经过它的指针,则行为是未定义的。

这定义了一个灵活的数组成员。

如果你考虑一下,这是有道理的。 指针算术和数组依赖于数组中相同大小的所有对象(因此a[i] == *(a + i)等等),所以拥有不同大小的对象数组会破坏指针算术。 指针数组不是问题,因为指针的大小都相同,即使指向的对象具有不同的大小。

如果你设法让编译器忽略违反的约束,那么数组的每个元素将具有零长度的灵活数组成员,因为结构将被视为具有没有数组成员的结构的大小(这是’最多的’情况下,灵活的数组成员被忽略’工作中的规则’。 但是编译器应该拒绝具有灵活数组成员的结构类型的数组; 这样的代码违反了约束(¶3在约束部分;¶18在语义部分)。