21

メニュー用に次の基本的なコードを作成しました。

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 ルールでコンパイルしています。

4

1 に答える 1

21

この方法による柔軟な配列メンバーの初期化は、C 標準では許可されていません。

C11: 6.7.2.1 構造体と共用体の指定子 (p20-21):

21 例 2 宣言の後:

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

構造体 structsには柔軟な配列メンバーがあり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

t2struct smember が含まれていないかのように扱われるため、の初期化は無効です(制約に違反しています) d。[...]

ただし、GCC では柔軟な配列の静的初期化が可能です。

GCC マニュアル: 6.17 長さゼロの配列:

代わりに、GCC は柔軟な配列メンバーの静的初期化を許可します。これは、データを格納するのに十分なサイズの配列が後に続く、元の構造体を含む新しい構造体を定義することと同じです。たとえば、以下でf1は、 は like と宣言されているかのように構築され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 } };
于 2015-01-09T00:38:35.213 に答える