Programmingシステムプログラマー

C言語における構造体のネストとアラインメント(構造体の整列)のメカニズムについて説明してください。構造体のサイズを制御する方法と、発生する可能性のある問題は何ですか?

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

回答。

C言語では、構造体(struct)は他の構造体や異なるデータ型を含むことができます。しかし、構造体内のフィールドの配置は、そのサイズとアラインメントに影響を与えることがあります。コンパイラは、最大のフィールドに合わせてアラインメントを保つために追加のバイト(パディング)を追加します。これはパフォーマンスとプロセッサの正しい動作にとって重要です。

構造体がネストされた構造体を含む場合、アラインメントは再帰的に適用されます:

  • 構造体のサイズは常に最も大きなフィールドのアラインメントの倍数になります。
  • ネストされた構造体は、sizeof(struct)がフィールドのsizeofの合計より大きくなる予期しないオフセットを引き起こす可能性があります。

サイズを制御する方法

  1. フィールドをサイズの降順に並べ替える。
  2. アラインメントディレクティブ(例えば、MSVCの #pragma pack やGCC/Clangの __attribute__((packed)))を使用する。

例:

#include <stdio.h> struct Inner { char c; int x; }; struct Outer { char a; struct Inner b; short s; }; int main() { printf("sizeof(struct Inner) = %zu\n", sizeof(struct Inner)); printf("sizeof(struct Outer) = %zu\n", sizeof(struct Outer)); return 0; } // sizeof(struct Inner) = 8 (64ビットの場合)、sizeof(struct Outer) = 16または24

packとpackedを使用すると、アラインメントを無視することによってサイズが減少しますが、これは一部のプラットフォーム(ARM、DSPなど)でパフォーマンスを低下させたりエラーを引き起こす可能性があります。


誘導的な質問。

質問: 同じ構造体のサイズがすべてのプラットフォームで同じであることを保証できますか?

回答: いいえ!C標準は同じアラインメントやバイトオーダー(エンディアン)を保証せず、フィールドの間や構造体の末尾にパディングを「追加」する可能性があります。構造体のバイナリ互換性を保つためには、アラインメントの手動管理を使用し、常に対象プラットフォームごとにsizeofを明示的にテストしてください。

例:

struct Data { char c; int x; }; // sizeof(Data)は通常64ビットで8、32ビットで5または8

歴史

マイクロコントローラ(ARM)とPC間でバイナリプロトコルを介して構造体を交換する際、ARMから受信したデータがPCで期待されるものと一致しなかったのは、異なるパディングとバイト順によるものでした。その結果、誤ったパラメータがデコードされ、デバイス制御に物理的なエラーが生じました。


歴史

ネットワークプロトコルでデータ送信の高速化のためにpacked構造体が追加されましたが、アラインメントのないプラットフォームでは個別のフィールドが機能しないことを考慮していませんでした(プロセッサがミスアラインドアクセスをサポートしていなかったため)。結論:ネットワークパケット処理中のハードウェア例外。


歴史

サーバーは構造体のレコードから成る外部ファイルで動作していました。コンパイラを更新した後、構造体のサイズが変更され(異なるアラインメント)、古いデータがファイルから正しく読み込まれなくなり、一部の情報が「壊れて」しまいました。