はじめに
C++の構造体(struct)は、全てのメンバ変数がそれぞれ個別のメモリ領域を持ちます。一方、「共用体 (union)」は、定義された全てのメンバ変数が、一つの同じメモリ領域を共有(共用)するという、特殊な性質を持っています。
これは、複数のデータ型のうち、常にどれか一つしか使わないことが分かっている場合に、メモリを節約するためのテクニックです。共用体のサイズは、その中で最も大きいメンバ変数のサイズになります。
この記事では、unionの基本的な使い方と、その「メモリ共有」という挙動について、サンプルコードで解説します。
union を使ったサンプルコード
このコードは、ProductCode(商品コード)という共用体を定義します。この共用体は、id(数値コード)とshortName(文字コード)という2つのメンバを持ちますが、どちらか一方しか有効な値として保持できません。
完成コード
#include <iostream>
using namespace std;
// 商品コードを格納する共用体の定義
union ProductCode {
int id; // 数値コード
char shortName[4]; // 3文字の英字コード (+ヌル文字)
};
int main() {
ProductCode code;
// --- 1. 整数メンバ(id)に値を設定 ---
cout << "最初に、数値コードとして 999 を設定します。" << endl;
code.id = 999;
// この時点では両方のメンバが同じメモリを見ている
cout << "数値コード(id): " << code.id << endl;
cout << "文字コード(shortName): " << code.shortName << " (※意味のないデータ)" << endl;
cout << "\n--- 2. 文字メンバ(shortName)に値を設定 ---" << endl;
cout << "次に、文字コードとして 'ABC' を設定します。" << endl;
code.shortName[0] = 'A';
code.shortName[1] = 'B';
code.shortName[2] = 'C';
code.shortName[3] = '\0'; // 終端ヌル文字
// shortNameに書き込んだことで、idの領域も上書きされた
cout << "文字コード(shortName): " << code.shortName << endl;
cout << "数値コード(id): " << code.id << " (※値が破壊された)" << endl;
return 0;
}
コードの解説
union ProductCode { ... };
union キーワードを使って、ProductCode という共用体を定義しています。int 型の id と、char[4] 型の shortName という2つのメンバを宣言していますが、これらは別々の場所ではなく、同じメモリ領域を異なる解釈で使う、という宣言になります。
メモリの共有
code.id = 999;:idメンバに999を代入すると、共用体のメモリ領域に999という数値データが書き込まれます。このときshortNameメンバを通じて同じメモリを覗くと、999のビットパターンを無理やり文字として解釈しようとするため、意味不明なデータが見えます。code.shortName[0] = 'A'; ...: 次に、shortNameメンバに"ABC"という文字データを書き込むと、共用体のメモリ領域はA,B,C,\0というビットパターンで上書きされます。その結果、元々あった999という数値データは破壊され、idメンバを通じて同じメモリを覗くと、"ABC\0"のビットパターンを無理やり数値として解釈した、全く異なる値が見えます。
このように、共用体では、最後に値を書き込んだメンバだけが有効なデータを保持し、それ以外のメンバにアクセスすると、意味のない(破壊された)データを読み込んでしまうことになります。
まとめ
今回は、C++の共用体 union の基本的な仕組みについて解説しました。
unionは、全てのメンバが同じメモリ領域を共有する。- そのため、同時に一つのメンバしか有効な値を保持できない。
- 複数のデータ型のうち、どれか一つだけを格納する場合のメモリ節約のために使われる。
共用体は、C言語との互換性や、非常に低レベルなメモリ操作など、限定的な場面で使われる特殊な機能です。ほとんどの場合、struct や、C++17で導入された std::variant を使う方が、より安全で分かりやすいプログラムになります。
