union
読み:ユニオン
外語:union
C/C++の予約語の一つ。共用体を定義する。
概要
同じメモリー領域を、異なる型の変数で参照できるようにするための機能。
実際に内容を参照する場合は構造体と同様に、共用体名.変数名、とする。
特徴
C
例えば8ビットのI/Oポートを定義するとし、そこに対してバイトアクセスと、ビット構造体アクセスを定義するとすると、次のようになる。
union tag_IOPORT {
unsigned char byPORT;
struct {
unsigned char B7:1;
unsigned char B6:1;
unsigned char B5:1;
unsigned char B4:1;
unsigned char B3:1;
unsigned char B2:1;
unsigned char B1:1;
unsigned char B0:1;
} BIT;
};
これをビットフィールドといい、こうすると、unsigned char byPORTと、ビット構造体BITが同じアドレスに配置される。
このI/Oポートがアドレス0xffffのメモリーマップドI/Oだとすると、次のように定義可能で、
#define IOPORT (*(volatile union tag_IOPORT *)0xffff)
こうすると、次の二通りのアクセスが可能となる。
IOPORT.byPORT = 0xaa;
IOPORT.BIT.B7 = 1;
GCC拡張
GCCでも、基本的にはCまたはC++の標準仕様と同様だが、「共用体のキャスト」「無名のフィールド」という二つの拡張が特徴となっている。clang/LLVMでも対応する。
共用体のキャスト
共用体で他の変数等を型キャストできる機能である。
typedef union { int i; double d; } uni_t;
int sample(int a, double b)
{
uni_t u;
if (a < b)
u = (uni_t)a; // is equal to u.i = a;
else
u = (uni_t)b; // is equal to u.d = b;
return u.i;
}
このように、unionでも型キャストが可能である。但しこのサンプル関数は、doubleが使われる条件となったときに正常な値を返さない。
無名のフィールド
C++では構造体や共用体の名前は必須ではなく、このような共用体は無名共用体や匿名共用体と呼ばれている。
GCC拡張では、Cの場合でも、構造体や共用体を別の構造体や共用体に埋め込む場合に限り、その内部の構造体や共用体に名前を付ける必要がない。またこの場合、参照する際にも構造体や共用体の名前を付けなくても内容にアクセスすることができる。
struct {
union {
unsigned int a;
float b;
};
} foo;
int main()
{
foo.b = 200.0;
printf("%x\n", foo.a);
return 0;
}
再検索