いけむランド

はてダからやってきました

Designated Initializer

指示初期化子の話。


指示初期化子というのは構造や配列の一部だけを初期化するように指定できる書き方で C99 で新機能として導入されたもので、今まで (C99 以前) は全部をがっつり初期化するか、宣言後に代入文で必要なメンバだけチマチマと設定していく必要があったものが、宣言文の一文で表現することができるようになった。詳しくは以下のサイトを参考されたい。


特に構造体変数の初期化でお世話になることが多そうな機能だが、構造体の構造によっては上手く適用できないことがある。例えば、cygwin では以下のコードがコンパイルできない。

#include <signal.h>
void func(void)
{
  struct sigaction action = { .sa_handler = SIG_IGN, .sa_flags = 0};
}
% gcc -c sigaction.c
sigaction.c: In function ‘func’:
sigaction.c:4: error: unknown field ‘sa_handler’ specified in initializer
%


何故かというと /usr/include/cygwin/signal.h における構造体 sigaction の定義が以下のようになっているからである。

typedef void (*_sig_func_ptr)(int);

struct sigaction
{
  __extension__ union
  {
    _sig_func_ptr sa_handler;           /* SIG_DFL, SIG_IGN, or pointer to a function */
    void  (*sa_sigaction) ( int, siginfo_t *, void * );
  };
  sigset_t sa_mask;
  int sa_flags;
};


sa_handler がさらに内部で union のメンバになっているからというオチである。

ちなみに普通にメンバに代入するように書くと、コンパイルできるのは何故なのだろうか? *1

#include <signal.h>
void func(void)
{
  struct sigaction action;
  action.sa_handler = SIG_IGN;
  action.sa_flags = 0;
}

*1:たしかに union に名前がないため、適切にアクセスするための名前がわからないが、これは仕様的に OK なのか? それともコンパイラ拡張なのか?