Namespaces
Variants

Union declaration

From cppreference.net

共用体(union)は、メンバーの記憶域が重複するシーケンスで構成される型です(これに対し、構造体(struct)はメンバーの記憶域が順序付けられたシーケンスで割り当てられる型です)。いずれかの時点で格納できる値は、多くとも1つのメンバーの値のみです。

共用体の 型指定子 は、使用されるキーワードを除いて struct 型指定子と同一です:

目次

構文

union attr-spec-seq  (オプション) name  (オプション) { struct-declaration-list } (1)
union attr-spec-seq  (オプション) name (2)
name - 定義されるunionの名前
struct-declaration-list - 任意の数の変数宣言、 ビットフィールド 宣言、およびstatic_assert宣言。不完全型のメンバーおよび関数型のメンバーは許可されません。
attr-spec-seq - (C23) オプションの 属性 リスト。union型に適用され、 (2) の形式では、その形式の後に ; が続かない場合(つまり前方宣言でない場合)は許可されません。

説明

共用体は、その最大のメンバを保持するのに必要なサイズのみを持ちます(追加の無名の末尾パディングが追加される場合もあります)。他のメンバは、その最大のメンバの一部として同じバイト内に割り当てられます。

共用体へのポインタは、その各メンバへのポインタにキャストできます(共用体がビットフィールドメンバを持つ場合、共用体へのポインタはビットフィールドの基底型へのポインタにキャストできます)。同様に、共用体の任意のメンバへのポインタは、包含する共用体へのポインタにキャストできます。

共用体の内容にアクセスするために使用されるメンバーが、最後に値を格納するために使用されたメンバーと同じでない場合、格納されていた値のオブジェクト表現は、新しい型のオブジェクト表現として再解釈されます(これは type punning として知られています)。新しい型のサイズが最後に書き込まれた型のサイズより大きい場合、超過するバイトの内容は未規定です(トラップ表現である可能性があります)。C99 TC3(DR 283)以前では、この動作は未定義でしたが、一般的にこの方法で実装されていました。

(C99以降)

structと同様に、名前のない共用体の型を持つ共用体の無名メンバは、 匿名共用体 として知られています。匿名共用体のすべてのメンバは、その共用体のレイアウトを維持したまま、外側のstructまたは共用体のメンバと見なされます。これは、外側のstructまたは共用体も匿名である場合、再帰的に適用されます。

struct v
{
   union // anonymous union
   {
       struct { int i, j; }; // anonymous structure
       struct { long k, l; } w;
   };
   int m;
} v1;
v1.i = 2;   // valid
v1.k = 3;   // invalid: inner structure is not anonymous
v1.w.k = 5; // valid

structと同様に、名前付きメンバ(匿名のネストされたstructまたは共用体を介して取得されたメンバを含む)なしで共用体が定義された場合、プログラムの動作は未定義です。

(C11以降)

キーワード

union

注記

構造体と共用体の初期化に関する規則については、 struct initialization を参照してください。

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
int main(void)
{
    union S
    {
        uint32_t u32;
        uint16_t u16[2];
        uint8_t  u8;
    } s = {0x12345678}; // s.u32 is now the active member
    printf("Union S has size %zu and holds %x\n", sizeof s, s.u32);
    s.u16[0] = 0x0011;  // s.u16 is now the active member
    // reading from s.u32 or from s.u8 reinterprets the object representation
//  printf("s.u8 is now %x\n", s.u8); // unspecified, typically 11 or 00
//  printf("s.u32 is now %x\n", s.u32); // unspecified, typically 12340011 or 00115678
    // pointers to all members of a union compare equal to themselves and the union
    assert((uint8_t*)&s == &s.u8);
    // this union has 3 bytes of trailing padding
    union pad
    {
        char  c[5]; // occupies 5 bytes
        float f;    // occupies 4 bytes, imposes alignment 4
    } p = { .f = 1.23 }; // the size is 8 to satisfy float's alignment
    printf("size of union of char[5] and float is %zu\n", sizeof p);
}

出力例:

Union S has size 4 and holds 12345678
size of union of char[5] and float is 8

不具合報告

以下の動作変更に関する欠陥報告書は、以前に公開されたC規格に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
DR 499 C11 匿名構造体/共用体のメンバーは、外側の構造体/共用体のメンバーと見なされていた それらはメモリレイアウトを保持する

参考文献

  • C23規格 (ISO/IEC 9899:2024):
  • 6.7.2.1 構造体及び共用体指定子 (p: 未定)
  • C17規格 (ISO/IEC 9899:2018):
  • 6.7.2.1 構造体および共用体指定子 (p: 81-84)
  • C11規格 (ISO/IEC 9899:2011):
  • 6.7.2.1 構造体および共用体指定子 (p: 112-117)
  • C99規格 (ISO/IEC 9899:1999):
  • 6.7.2.1 構造体および共用体指定子 (p: 101-104)
  • C89/C90標準 (ISO/IEC 9899:1990):
  • 3.5.2.1 構造体および共用体指定子

関連項目

C++ ドキュメント for Union 宣言