共用体
ひとつの領域、複数の変数
構造体に類似した機能で共用体と呼ばれるものがあります
共用体は、ひとつのメモリ領域に複数の変数を割り当てます
ただし、共用体に割り当てた全ての変数のアドレスは同じです
そのため使用できる変数は1つまでです
共用体を作成するにはunionキーワードを使用します
構文は構造体と同じです
union タグ名{
型 メンバ名;
...
} 共用体変数名;
共用対のメンバは、全て同じメモリ空間に割り当てられます
ひとつのメンバの値を変更すると、当然他のメンバの値もそれに従います
共用対のメンバへのアクセスも構造体同様、ドット演算し、またはアロー演算子を用います
ポインタの使用も構造体と同じです
共用体変数名.メンバ名;
共用大変数名->メンバ名;
以下は、簡単な共用体の作成と使用のサンプルです
#include <stdio.h>
union UNION {
char ch;
int n;
double m;
};
int main() {
union UNION obj;
obj.m = 0;
obj.ch = '@';
printf("%c : %d : %g\n" , obj.ch , obj.n , obj.m);
obj.n++;
printf("%c : %d : %g\n" , obj.ch , obj.n , obj.m);
obj.m = 3.26083e-322;
printf("%c : %d : %g\n" , obj.ch , obj.n , obj.m);
return 0;
}
共用体UNIONを作成して、それぞれ型の違うch , n , mというメンバを宣言しています
それぞれのメンバは型とサイズを持っていますが、メモリ領域は全て同じです
バイト単位のビットフィールドのようなものです
共用体UNION
<-------------double m------------->
|
---|
この時、共用体のサイズはコンパイル時に決定されメンバの中でもっとも大きい型になります
(必ずしもそうなるわけではなく、一部の環境によってはワード単位で振り分けられることもある)
上のプログラムの場合 double なので、この共用体は8バイトのサイズになります
結果は次のようになりました
@ : 64 : 3.16202e-322
A : 65 : 3.21143e-322
B : 66 : 3.26083e-322
確保されている共用体のサイズは、もっともサイズの大きいdouble型の8バイトですが
chやnへのアクセスは、ビット数が制限され型に合わされます
つまり、chへアクセスした場合は8バイトのうち下位8ビットまでしか参照できません
その共用体がint型の320という値を確保していても、char型のメンバにアクセスした場合64という結果になります
0000 0010 1000 0000 -> 1000 0000
次のプログラムは、共用体のint型メンバに320を代入し
同じ共用体のchar型メンバを出力したプログラムです
#include <stdio.h>
union UNION {
char ch;
int n;
};
int main() {
union UNION obj;
obj.n = 320;
printf("%d" , obj.ch);
return 0;
}
結果は先ほど説明したとおりになります
次のプログラムは、共用体のメンバがすべて同じアドレスを参照していることを表します
さらに、共用体のポインタ、及びポインタからアロー演算子を使ったアクセスに注目してください
#include <stdio.h>
union UNION {
char ch;
int n;
double m;
};
int main() {
union UNION obj , *po;
printf("%x : %x : %x\n" , &obj.ch , &obj.n , &obj.m);
po = &obj;
po->n = 65;
printf("%c : %d : %g\n" , po->ch , po->n , po->m);
return 0;
}
このように、共用体の扱いは構造体を理解していれば難しいことはありません
しかし、その内部動作はまったく違うので、ビットレベルでプログラムの動きを把握してください
union [tag] {member-list} [declarators];
共用体を宣言します
共用体は、型の異なる変数を同じのメモリ領域に宣言します
tag - 省略可能です。スコープないで共用体変数を新しく宣言するのに使用します
member-list - メンバ変数を宣言します
declarators - 変数を宣言します