ProgrammingC ソフトウェア開発者

Cにおける構造体の初期化はどのように実現されますか?さまざまな初期化方法、フィールドの初期化順序、部分的な初期化、ネストされた構造体との関係で遭遇する可能性のある落とし穴について説明してください。

Hintsage AIアシスタントで面接を突破

回答

Cには、構造体を初期化するいくつかの方法があります:

  1. 標準初期化(順序付き):
struct Point { int x, y; }; struct Point p = {10, 20};

フィールドは宣言された順序で初期化されます。

  1. 名前付きフィールドによる初期化(C99+):
struct Point p = {.y = 20, .x = 10};

任意の順序でフィールドを初期化できます。

  1. 部分的初期化: すべてのフィールドが明示的に指定されていない場合、残りは自動的にゼロで初期化されます。
struct Rect { int x, y, w, h; } r = {1, 2}; // w と h は 0
  1. ネストされた構造体: ネストされた構造体の初期化には、すべてのネストされた値を順番(または名前で)指定する必要があります。
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}};

落とし穴:

  • 順序付き初期化時にフィールドの順序を間違えやすい。
  • 部分的初期化は、ネストされたポインタを含む構造体には常に安全ではなく、その場合、未初期化のポインタは明示的に初期化するか、構造体が静的またはグローバルなストレージ領域を持つ場合にのみNULLになります。
  • 型が変更された場合(例えば、構造体の先頭に新しいフィールドが追加された場合)、古い初期化は予期しない結果をもたらします。

質問のトリック

質問: 構造体の初期化時に、すべてのフィールドを明示的に指定しない場合、構造体が自動的なローカル変数として宣言されているとどうなりますか?

期待される誤った回答: "残りのフィールドは常にゼロになります。"

正しい回答: 自動(ローカル)変数は、明示的に初期化されていない場合、未初期化の値のままです。部分的初期化は明示的に記述されたフィールドのみを初期化し、残りは 未定義の値 になります(= {...}による初期化の例外として、残りは静的またはグローバル構造体の場合のみゼロになります)。

例:

void foo() { struct Point { int x, y, z; } p = {1}; // p.x == 1, p.y および p.z == 0 (これは = {1}; の場合のみ) }

実際のエラーの例


物語

グラフィックスエンジンのプロジェクトで頂点構造体の先頭にフィールドを追加しましたが、異なるモジュールでのオブジェクトの初期化方法を再検討しませんでした。その結果、半分のモジュールが色や座標を誤って初期化し、表示アーティファクトとして現れました。


物語

ビデオ処理ハンドラーでネストされたポインタを持つ構造体が部分的に初期化され、これはグローバル変数には正しいですが、ローカルにはそうではありませんでした。その結果、ポインタは「ゴミ」を含み、不正なアドレスでの操作や難解なクラッシュにつながりました。


物語

大きな構造体に新しいフィールドを追加する際に、著者たちは古いコードセクションを更新せず、順序初期化が行われました。フィールドと初期化子の順序が一致しなかったため、重要な変数が不正な値を取得しました。その原因を特定するために、構造体の監査と名前付き初期化の導入が必要でした。