union foo {
int a; // can't use both a and b at once
char b;
} foo;
struct bar {
int a; // can use both a and b simultaneously
char b;
} bar;
union foo x;
x.a = 3; // OK
x.b = 'c'; // NO! this affects the value of x.a!
struct bar y;
y.a = 3; // OK
y.b = 'c'; // OK
ユニオンでは、すべての要素が同じ場所に格納されているため、いずれかの要素だけを使用することになります。そのため、複数の型になる可能性があるものを格納したい場合に便利です。一方、構造体は、要素ごとに独立したメモリの場所を持ち、すべての要素を一度に使用することができます。
具体的な使用例を挙げると、私は少し前にSchemeのインタープリタを作っていて、C言語のデータ型の上にSchemeのデータ型を重ねていました。これは、構造体に値の型を示すenumと、その値を格納するunionを格納するというものだ。
編集: x.bを 'c'に設定するとx.aの値が何に変わるのか気になるところですが、技術的には未定義です。最近のマシンでは、charは1バイト、intは4バイトなので、x.bに 'c'という値を与えると、x.aの第1バイトにも同じ値が与えられます。
プリント
なぜこの2つの値は同じなのでしょうか?int 3の最後の3バイトはすべて0なので、99とも読めるからです。x.aにもっと大きな数字を入れると、必ずしもそうではないことがわかります。
プリント
実際のメモリの値を詳しく見るために、16進数で設定してプリントアウトしてみましょう。
プリント
0x22が0xEFを上書きしているのがよくわかります。
BUT。
このプログラムは、私のMacでは0xEFを0x22に上書きしましたが、他のプラットフォームではintを構成するバイトの順序が逆なので、代わりに0xDEに上書きされてしまうことがあります。したがって、プログラムを作成する際には、ユニオン内の特定のデータを上書きするという動作は、ポータブルではないので、決して当てにしてはいけません。
バイトの順序についての詳しい読み物は、endiannessをご覧ください。
"union"と"struct"は、C言語の構造体です。どちらかのキーワードを使用した場合に異なるコードを生成するのはコンパイラなので、両者の違いをOSレベルで語るのは不適切です。
構造体では、その中のすべての要素の合計サイズが割り当てられます。
ユニオンは、最大のメンバーが必要とする量のメモリを割り当てます。