Cには、構造体を初期化するいくつかの方法があります:
struct Point { int x, y; }; struct Point p = {10, 20};
フィールドは宣言された順序で初期化されます。
struct Point p = {.y = 20, .x = 10};
任意の順序でフィールドを初期化できます。
struct Rect { int x, y, w, h; } r = {1, 2}; // w と h は 0
struct Color { int r, g, b; }; struct Pixel { struct Point pos; struct Color col; }; struct Pixel px = {{10,20}, {255,0,0}};
名前付き初期化を使用すると、エラーを回避できます:
struct Pixel px = {.col = {.r = 255, .g = 0, .b = 0}};
落とし穴:
質問: 構造体の初期化時に、すべてのフィールドを明示的に指定しない場合、構造体が自動的なローカル変数として宣言されているとどうなりますか?
期待される誤った回答: "残りのフィールドは常にゼロになります。"
正しい回答: 自動(ローカル)変数は、明示的に初期化されていない場合、未初期化の値のままです。部分的初期化は明示的に記述されたフィールドのみを初期化し、残りは 未定義の値 になります(= {...}による初期化の例外として、残りは静的またはグローバル構造体の場合のみゼロになります)。
例:
void foo() { struct Point { int x, y, z; } p = {1}; // p.x == 1, p.y および p.z == 0 (これは = {1}; の場合のみ) }
物語
グラフィックスエンジンのプロジェクトで頂点構造体の先頭にフィールドを追加しましたが、異なるモジュールでのオブジェクトの初期化方法を再検討しませんでした。その結果、半分のモジュールが色や座標を誤って初期化し、表示アーティファクトとして現れました。
物語
ビデオ処理ハンドラーでネストされたポインタを持つ構造体が部分的に初期化され、これはグローバル変数には正しいですが、ローカルにはそうではありませんでした。その結果、ポインタは「ゴミ」を含み、不正なアドレスでの操作や難解なクラッシュにつながりました。
物語
大きな構造体に新しいフィールドを追加する際に、著者たちは古いコードセクションを更新せず、順序初期化が行われました。フィールドと初期化子の順序が一致しなかったため、重要な変数が不正な値を取得しました。その原因を特定するために、構造体の監査と名前付き初期化の導入が必要でした。