1. ホーム
  2. c

[解決済み] なぜコンパイラはこのような警告を出すのですか?"missing initializer" という警告が出るのはなぜですか?構造体は初期化されていないのでしょうか?

2023-07-31 09:29:38

質問

あるプログラムのフロントエンドのようなものを作っています。プログラムを起動するために、次の呼び出しを使用しています。 CreateProcess() へのポインタを受け取ります。 STARTUPINFO 構造体へのポインタを受け取ります。構造体を初期化するために、私は以前はこうしていました。

STARTUPINFO startupInfo = {0}; // Or even '\0'.
startupInfo.cb = sizeof(startupInfo);

GCCでプログラムをコンパイルするとき、これらの警告のセットを有効にします。 -Wall -Wextra でコンパイルすると、最初の行を指しているイニシャライザがないという警告が出されます。

warning: missing initializer
warning: (near initialization for 'startupInfo.lpReserved')

ということで、結局は

STARTUPINFO startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);

そしてこの方法では、コンパイラは何の警告も出しません。 問題は、構造体を初期化するこれらの方法の違いは何なのか、ということです。 最初の方法を使うと、構造体は初期化されないのでしょうか? どちらがお勧めですか?

どのように解決するのですか?

しかし、GCCのメンテナがCのニュアンスについて私よりもずっと多くのことを知っていることは確かです。

GCC メーリングリストのこの問題についての小さなスレッドを参照してください。

肝心な点ですが、構造体を初期化する際に、単に {0} だけで構造体を初期化すると、実際には全体がゼロ初期化されます。

C99規格では、6.7.8/21 "初期化 - Sematics"で次のように書かれています。

中括弧で囲まれたリスト内の初期化子が集合体の要素やメンバよりも少ない場合、または、既知のサイズの配列を初期化するために使用される文字列リテラルの文字数が配列内の要素よりも少ない場合、集合体の残りは、静的記憶期間を持つオブジェクトと同様に暗黙的に初期化されなければならない。

C90 は 6.5.7 で少し異なる表現で本質的に同じことを言っています (言い換えれば、C99 はここに新しいものを追加していません)。

また、C++では、これは中括弧の空のセット、".C++、".C++に拡張されたことに注意してください。 {} というのは、(テンプレートのように)型のメンバやメンバ数が分からない場合があるからです。 そのため、オブジェクトが持つ可能性のあるメンバーの数よりも短いイニシャライザー リストを持つことは、良い習慣であるだけでなく、時には必要なことでもあるのです。