Programming組み込み/低レベルC開発者

C言語における共用体(union)の動作について説明してください。共用体を使用して解決される問題は何ですか?正しく使う方法と、使用時に遭遇する典型的な落とし穴は何ですか?

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

回答

共用体(union)は、同じメモリ領域に異なる値を保存する特別なデータ型です。共用体では、すべてのメンバーが同じアドレスに配置され、メモリのサイズは最も大きなメンバーのサイズと等しくなります。

使用法:

  • 変数が同時に複数の型の値のいずれかを取る場合、メモリの節約に便利です;
  • 同じビットを異なる方法で解釈することができます(例:低レベルアクセスまたはプロトコルのため)。

例:

union Data { int i; float f; char s[4]; }; union Data d; d.i = 0x41424344; // メモリには現在4バイトがあり、int、float、文字列として読み取ることができる printf("%c%c%c ", d.s[0], d.s[1], d.s[2]); // ベンダー特有の出力

落とし穴と使用ルール:

  • 共用体には、常に1つの「有効な」フィールドだけを保持してください。
  • どのフィールドが最後に「アクティブ」だったかを自動的に追跡することはありません。
  • 非アクティブなフィールドを読み取ることは 未定義の動作 です。
  • プラットフォームのバイトオーダー(エンディアン)が非常に重要です。

クイズ的な質問

質問: 共用体を使用する意味は何ですか?複数のフィールドを持つ構造体を単に使用できるのではないですか?

回答: 共用体の使用はメモリを節約します。なぜなら、いつでも内部にただ1つの値しか保持されないからです。構造体では、各フィールドにメモリが割り当てられますが、共用体では最大のフィールドに対してのみメモリが割り当てられ、残りはそのメモリを「共有」します。また、共用体は同じメモリのフラグメントでの異なるデータ表現間での安全または意図的な変換を可能にします。

例:

struct S { int i; float f; } s; // sizeof = sizeof(int) + sizeof(float) union U { int i; float f; } u; // sizeof = max(sizeof(int),sizeof(float))

実際のエラーの例


物語

デバイスドライバプロジェクトで、データへのビットアクセスを使用した共用体を介して「ハードウェア」との通信が行われていました。小さなリファクタリングの後、開発者は共用体の異なるフィールドの1つに書き込むことを忘れ、不正確なデータの読み取りや致命的なシステムクラッシュを引き起こしました。共用体では、いつでも「本物」であるフィールドは1つだけです。


物語

ネットワークパケットを共用体を介して交換する際、メモリ管理を行っていた開発者が構造体のアライメントを考慮するのを忘れました。その結果、1バイトのオフセットが発生し、構造体が不正なオフセットで解析され、プロトコルがオリジナルと互換性がなくなりました。


物語

シリアル化ライブラリの作成中に、プログラマーは共用体を値として関数に渡しましたが、読み取りの前に必要なフィールドが初期化されていませんでした。そのため、データが不正にシリアル化され、出力ストリームにゴミが発生し、元の情報の復元が不可能になりました。