組み込みC言語の共用体解説:効率的なメモリ共有とメッセージング
組み込みC言語における共用体の理解
組み込みシステムにおいて、共用体は異なるデータ型を同じメモリ位置に格納できる強力なデータ構造です。この記事では共用体の基礎を解説し、実践的な例を示し、メモリ制約と帯域幅に敏感なアプリケーションでなぜ定番ツールなのかを説明します。
組み込みCにおける構造体と共用体の違い
以前、構造体について説明しました:異種の変数を単一のエンティティにグループ化する方法です。C言語では、共用体も異なる型をグループ化する補完的な構成要素ですが、重要な違いは各メンバが同じメモリアドレスを共有することです。
導入例
共用体の宣言は構造体とほぼ同じで、structをunionに置き換えるだけです:
union test { uint8_t c; uint32_t i; };
このテンプレートは2つのメンバを定義します:cは1バイト、iは4バイトを占有します。この型の変数を作成するには:
union test u1;
メンバへのアクセスにはドット演算子を使用します:
u1.i = 10; m = u1.c; // mはuint8_tでなければならない
共用体のストレージサイズは最大メンバのサイズと等しいため、u1は4バイトを占有します。iへの書き込みはcが使用する同じメモリを上書きするため、2つのメンバは相互排他的です。
共有メモリ空間は必要か?
2台の組み込みデバイスデバイスAとデバイスBがステータス、速度、位置データを交換するシナリオを想像してください(図1参照)。データ項目とサイズは以下の通り:

図1
| 変数 | サイズ(バイト) | 意味 |
|---|---|---|
| power | 1 | バッテリー充電 |
| op_mode | 1 | 動作モード |
| temp | 1 | 周囲温度 |
| x_pos | 2 | X座標 |
| y_pos | 2 | Y座標 |
| vel | 2 | 速度 |
デバイスBがすべての情報を必要とする場合、単純な構造体では9バイト必要で、各通信ラウンドで9バイトフレームを転送します(図2参照)。しかし現実的な多くのシナリオでは、3つのメッセージタイプは相互排他的です:時にはステータスのみ、時には位置のみ、時には速度のみ。その場合、最大ペイロードは4バイト(位置メッセージ)です。4バイトバッファを共有する共用体なら、3つのメッセージのいずれかを保持でき、フレームサイズを9バイトから4バイトに削減できます(図3参照)。

図2

図3
メッセージパケットへの共用体の利用
以下ではステータス用と位置用の2つの構造体を作成し、速度フィールドとともに共用体に埋め込みます:
struct status_s { uint8_t power; uint8_t op_mode; uint8_t temp; }; struct position_s { uint16_t x_pos; uint16_t y_pos; }; union msg_union { struct status_s status; struct position_s position; uint16_t vel; };
共用体のサイズは4バイト(position_sのサイズ)で、3つのメッセージタイプすべてで共有されます。
共用体のアクティブメンバを追跡する方法
受信側が共用体を読み取る際、どのメンバが有効かを知る必要があります。一般的なパターンはタグ付き共用体:アクティブなメンバを記録する別フィールドを設けることです。共用体の前に1バイトのmsg_typeを追加できます:
struct message_s { uint8_t msg_type; // 's' = ステータス, 'p' = 位置, 'v' = 速度 union { struct status_s status; struct position_s position; uint16_t vel; } msg; };
msg_typeバイトを共用体とともに送信することで、受信側はペイロードの形状を事前に知らなくても正しく解釈できます。
代替案:動的メモリ割り当て
別のアプローチは、各メッセージタイプごとにメモリを動的に割り当てることです。送信側はmsg_typeを設定し、そのペイロードに必要なバイト数だけ割り当てます。受信側はmsg_typeに基づいて着信データを解釈し、終了時にメモリを解放します。これはわずかにメモリ効率が良いかもしれませんが、動的割り当ては実行時オーバーヘッドと明示的な解放の必要性を導入するため、多くの組み込み開発者は静的共用体戦略を好みます。
次回:共用体の応用
共用体は、より大きなワードから小さなデータ片を抽出するためにも頻繁に使用されます。これは通信プロトコルやハードウェアレジスタの解析で特に価値があります。次回の記事ではそれらのユースケースに深く潜ります。
組み込みCに関する記事をさらに探すには、記事インデックスをご覧ください。
埋め込み
- クラウド×IoTの力を解き放つ:シームレスな接続とデータインサイトの実現
- ロボットプログラミングの理解:3つの主要手法を解説
- マイクロプロセッサプログラミングの基礎
- 2021年 必ず学ぶべき9つのプログラミング言語:Go、Rust、Kotlinなど注目言語を解説
- コンプレッサー単位のマスター:一般的な測定用語の明確なガイド
- 組み込みシステムプログラミング:言語、アーキテクチャ、応用
- 産業用IoTソリューションに最適なプログラミング言語の選び方
- 「信頼性のインターネット」におけるデータ活用:効果的管理のための戦略
- IoTの民主化:次世代衛星IoTがもたらす普遍的で手頃な接続性
- データセンターの未来:トレンド、技術、持続可能性
- C言語共用体:複数データ型の効率的なメモリ管理