c-为什么具有灵活数组成员的结构的初始化无效,而对于固定大小的数组成员有效



C标准状态(强调mine):

21示例2声明后:

struct s { int n; double d[]; };

结构结构体CCD_ 1具有一个灵活的数组成员CCD_。[…]


22根据上述声明:

struct s t1 = { 0 };         // valid
struct s t2 = { 1, { 4.2 }}; // invalid
t1.n = 4;                    // valid
t1.d[0] = 4.2;               // might be undefined behavior

t2的初始化无效(违反了约束),因为struct s被视为不包含成员d

来源:C18,§6.7.2.1/20+/21

我不理解">,因为CCD_ 6被当作不包含成员CCD_;

如果我使用{ 1, { 4.2 }};的初始化器,{ 4.2 }部分是初始化灵活数组成员;准确地说,将灵活数组成员初始化为由一个元素组成,并将该元素初始化为值s0,从而将stuct s视为具有成员d

这句话在我看来毫无意义。

  • 为什么标准说{ 4.2 }不会初始化/表示灵活数组成员,因此该结构将被视为没有成员d

如果我使用一个固定大小的数组,这个表示法可以正常工作,并且初始化成员时不会抱怨:

struct foo {
int x;
double y[1];
};
int main (void)
{
struct foo a = { 1, { 2.3 } };
}

证据

  • 为什么当结构具有灵活的数组成员时此初始化无效,而当结构具有固定大小的数组成员时此初始化有效

你能详细说明一下吗?


我读过:

为什么灵活数组成员的静态初始化有效?

如何初始化具有灵活阵列成员的结构

灵活的数组成员会导致未定义的行为吗?

还有其他人,但他们都没有回答我这句话想解释什么,以及为什么这句话是无效的。


相关:

  • 具有灵活数组成员的结构数组的行为如何
  • 灵活阵列成员的真正好处是什么

我想这是一个语言缺陷。虽然初始化一个灵活的数组成员可能没有意义,但标准需要在某个地方解决这个问题。我在任何地方都找不到这样规范的文本。

柔性阵列成员的定义是,C17 6.7.2.1/18:

特殊情况下,具有多个命名成员的结构的最后一个元素可能具有不完全数组类型;这被称为灵活数组成员。在大多数情况下,灵活的阵列成员被忽略。特别地,该结构的尺寸就好像柔性阵列构件省略,只是它可能具有比省略所暗示的更多的尾部填充。

从中我们了解到,灵活的数组成员是不完整的数组类型。然而,除了在计算结构的大小时,我们没有了解在什么情况下会忽略灵活的数组成员"在大多数情况下;这是没有帮助的,也是缺陷所在——这需要扩展到一个详尽的列表,包括灵活数组成员作为初始值设定项列表一部分时的行为。否则,可能会认为它的行为与任何其他不完整类型的数组一样。

C17 6.2.5/22:

未知大小的数组类型是不完整的类型。

然后初始化规则说,C17 6.7.9:

要初始化的实体的类型应为未知大小的数组或不是可变长度数组类型的完整对象类型。

到目前为止,还没有规范性的文本表明我们不允许为灵活的数组成员提供初始值设定项,相反。问题中的示例(C17 6.7.2.1示例21)不规范,因为示例在ISO标准中不规范。该示例没有提到违反了哪个约束,也没有提到必须忽略灵活数组成员的位置。

我想我可能会就此提交一份DR。

我不明白"因为结构s被视为不包含成员d";。

C标准还说"在大多数情况下,会忽略灵活的数组成员。"目前还不清楚为什么您不理解这是什么。如果struct s被声明为struct s { int n; double d[]; };,那么在大多数情况中,C实现的行为就像它被声明为struct s { int n; };一样。因此,struct s t2 = { 1, { 4.2 }};失败是因为4.2是实际上不存在的东西的初始化器。

明智的做法是询问为什么会出现这种情况。在大多数情况下,我希望编译器能够支持一个定义,在该定义中,数组初始值设定项被计数并用于设置结构大小。当然,编译器使用d0这样的数组定义来实现这一点。但是,对于灵活的阵列成员来说,这不是典型的用例。通常,程序接收关于它将需要用该结构管理多少元素的信息,为该结构分配空间,其中包括用于这些元素的空间,然后将一个结构放入所分配的空间中。也就是说,具有灵活阵列成员的结构的典型用例是具有动态分配的空间。我预计C委员会几乎没有必要要求编译器在静态或自动对象中支持灵活的数组成员,而不是动态对象。

您在引用的示例中省略了一些重要的语言-以下是全文:

20示例2声明之后:

struct s { int n; double d[]; };
结构CCD_ 21具有柔性阵列构件CCD_ 22一种典型的使用方法是:

int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
并且假设对malloc的调用成功,则p所指向的对象在大多数情况下表现为p已声明为:

struct { int n; double d[m]; } *p;
(在某些情况下,这种等价性被破坏;特别是,成员d的偏移可能不相同)

IOW,只有动态分配struct实例并为数组成员分配额外空间,灵活的数组成员才能真正发挥作用。

灵活的数组成员没有大小,因此它对struct类型的大小没有贡献——也就是说,sizeof (struct s)的结果计算为没有数组的类型的大小。

IMO这是因为当结构体声明为extern时,无法在另一个编译单元中确定以这种方式初始化的结构体的sizeof

最新更新