为什么灵活数组成员的静态初始化会起作用?

25

我已经编写了以下用于菜单的基本代码:

typedef struct Menu {
    char* title;
    unsigned num_submenus;
    struct Menu *submenu[];
} Menu;

Menu sub1 = {"Submenu 1", 0, {NULL}};
Menu sub2 = {"Submenu 2", 0, {NULL}};
Menu Main = {"Main Menu", 2, {&sub1, &sub2}};   /* No Error?! */

int main()
{
    printf("%s\n", Main.title);
    printf("%s\n", Main.submenu[0]->title);
    printf("%s\n", Main.submenu[1]->title);
}

浏览一些相关问题,似乎使用柔性数组成员的唯一方法是对其动态分配内存。但是我的编译器可以很好地编译和运行代码,没有任何错误或警告。这是不被允许的吗?

我正在使用MinGW GCC 4.6.1,并遵循C99规则进行编译。


你期望出现什么错误? - Ismail Badawi
3
你是否使用了 -pedantic 进行编译?这会导致一个错误。 - Iharob Al Asimi
clang++ 11.0.0 给出的错误信息是:error: initialization of flexible array member is not allowed - Danijel
1个回答

24

按照C标准,不允许以这种方式初始化柔性数组成员。

C11: 6.7.2.1 结构体和共用体规范 (p20-21):

21 示例 2 在声明后:

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

结构体s具有一个灵活数组成员d。[...]

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。[...]

但是,GCC允许灵活数组的静态初始化:

GCC手册:6.17长度为零的数组:

相反,GCC允许对灵活数组成员进行静态初始化。这相当于定义一个包含原始结构和足够大小以包含数据的数组的新结构。例如,在以下示例中,f1的构造方式就像声明f2一样。

 struct f1 {
   int x; 
   int y[];
 } f1 = { 1, { 2, 3, 4 } };

 struct f2 {
   struct f1 f1; 
   int data[3];
 } f2 = { { 1 }, { 2, 3, 4 } };

啊,是的,“static”这个词我漏掉了。不管怎样,这段代码除了GCC之外,其他编译器是否允许? - thndrwrks
2
@thndrwrks;请查看更新。标准不允许对不定长数组进行静态初始化。 - haccks
@nyholku; n1570: §6.7.2.1/18*[...]在大多数情况下,弹性数组成员被忽略。特别地,结构体的大小就像弹性数组成员被省略一样,除了它可能有比省略所暗示的更多的尾部填充。[...]* - haccks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接