Почему статическая инициализация элемента гибкого массива работает?

Я написал следующий базовый код для меню:

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.

Ответ 1

Инициализация гибкого элемента массива таким образом запрещена по стандарту C.

C11: 6.7.2.1 Спецификаторы структуры и объединения (p20-21):

21 ПРИМЕР 2 После объявления:

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

структура struct 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 } };