構造体のメンバへの値への代入2

昨日の続き。デバイスドライバでは構造体のメンバに構造体、しかも数が可変する構造体のメンバを入れているのだ。昨日のマクロを使って可変のメンバを一度に初期化する構造体のサンプルを書いてみた。

#include<stdio.h>

struct test {
  int val_a;
  int val_b;
};

struct top {
  int num_tests;
  struct test tests[];
};

#define TEST(a, b) \
{                  \
    .val_a = a,    \
    .val_b = b,    \
}

int main(int argc,char **argv){

  /* staticを付けた場合のみコンパイルが通る */
  static struct top top = { 
    .num_tests = 2 ,
    .tests = {TEST(1,2), TEST(3,4)}
  };

  printf ("top.num_tests= %d\n", top.num_tests);

  for(int i=0; i< top.num_tests; i++){
    printf("top.tests[%d].val_a= %d, top.tests[%d].val_b= %d\n",
  	   top.num_tests,
  	   top.tests[i].val_a,
  	   top.num_tests,
  	   top.tests[i].val_b);
  }

  return 0;
}

ここで注意したいのが、可変数の構造体を実体化する時に、必ず"static"を付けなければいけないこと。そうでないと以下のエラーが発生してしまう。

hoge3.c: 関数 ‘main’ 内:
hoge3.c:26:5: エラー: non-static initialization of a flexible array member
hoge3.c:26:5: エラー: (‘top’ 用の初期化付近)

またforループで内部参照するには、C99の標準に従う旨をビルドオプションに指定する必要があった。そうしないと以下のエラーが発生する。

$ gcc hoge3.c
hoge3.c: 関数 ‘main’ 内:
hoge3.c:31:3: エラー: ‘for’ ループ初期化宣言は C99 モード内でのみ許可されています
hoge3.c:31:3: 備考: オプション -std=c99 または -std=gnu99 をコードコンパイル時に使用してください

C99の99というのは1999年に拡張された規格という意味。

ANSI-CとC99とGCCの拡張文法

2chでも以下のメモがあった。

http://2chland.net/tech/1147183708-450.html

デフォルトの名無しさん [sage]2006/05/24(水) 00:34:07

構造体の中のサイズなし配列は、C99より前では違反、C99から合法。
初期化方法については資料が手元にないので知らん。 

C99でのコンパイルは以下で通った。ビルドオプションと出力は以下。

$ gcc -std=c99 hoge3.c
$ ./a.out 
top.num_tests= 2
top.tests[2].val_a= 1, top.tests[2].val_b= 2
top.tests[2].val_a= 3, top.tests[2].val_b= 4
$ gcc -std=c99 hoge3.c

This is a memo about initializing variable members of a structure in C.