名前空間
変種
操作

共用体宣言

From cppreference.com
< c‎ | language

共用体とは、格納域が重なり合う(格納域が順序付けられたシーケンスで割り当てられる構造体とは対照的に)一連のメンバで構成される型です。共用体には、一度に最大で1つのメンバの値を格納できます。

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

目次

[編集] 構文

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

[編集] 説明

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

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

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

(C99以降)

構造体と同様に、nameのない共用体型の無名メンバは「匿名共用体」として知られています。匿名共用体のすべてのメンバは、共用体のレイアウトを保持しながら、囲む構造体または共用体のメンバであると見なされます。これは、囲む構造体または共用体も匿名である場合に再帰的に適用されます。

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

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

(C11 以降)

[編集] キーワード

union

[編集] 注記

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

[編集]

#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: TBD)
  • 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++ ドキュメント 共用体宣言
English 日本語 中文(简体) 中文(繁體)