命名空間
變體
動作

Union 宣告

出自 cppreference.com
< c‎ | 語言

Union(共用體)是一種由一系列成員組成的型別,這些成員的儲存空間會重疊(與 struct 相反,struct 是由一系列按順序分配儲存空間的成員組成的型別)。Union 在任何時間點最多只能儲存其中一個成員的值。

Union 的 型別指定子 (type specifier)struct 的型別指定子相同,僅使用的關鍵字不同。

目錄

[編輯] 語法

union attr-spec-seq (選擇性) name (選擇性) { struct-declaration-list } (1)
union attr-spec-seq (選擇性) name (2)
name (名稱) - 正在定義的 union 名稱
struct-declaration-list - 任意數量的變數宣告、位元欄位 (bit-field) 宣告以及靜態斷言 (static assert) 宣告。不允許使用不完整型別的成員或函式型別的成員。
attr-spec-seq - (C23) 應用於 union 型別的選擇性屬性列表。若後方未接 ;(即非前向宣告),則不允許用於 (2) 的形式。

[編輯] 說明

Union 的大小僅需足以容納其最大的成員(可能還會增加額外的未命名尾隨填充)。其他成員會被分配在與該最大成員重疊的相同位元組中。

指向 union 的指標可以轉型為指向其任一成員的指標(如果 union 具有位元欄位成員,則指向 union 的指標可轉型為指向該位元欄位底層型別的指標)。同樣地,指向 union 任一成員的指標也可以轉型為指向該包含它的 union 的指標。

若用於存取 union 內容的成員與最後一次用於儲存值的成員不同,則所儲存值的物件表示會被重新詮釋為新型別的物件表示(這稱為型別雙關,type punning)。如果新型別的大小大於最後寫入型別的大小,則超出部分的位元組內容是不明確的(且可能成為陷阱表示,trap representation)。在 C99 TC3 (DR 283) 之前,此行為是未定義的,但通常以這種方式實作。

(自 C99 起)

與 struct 類似,一種型別為不含 name 之 union 的未命名 union 成員被稱為匿名 union (anonymous union)。匿名 union 的每個成員都被視為包含它的 struct 或 union 的成員,並保留其 union 的佈局。若外層的 struct 或 union 也是匿名的,則此規則遞迴適用。

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 類似,若定義的 union 不包含任何具名成員(包括透過匿名巢狀 struct 或 union 獲得的成員),則程式行為未定義。

(自 C11 起)

[關鍵字]

union

[註解]

關於 struct 和 union 初始化規則,請參閱 struct 初始化

[範例]

#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 匿名 struct/union 的成員被視為外層 struct/union 的成員 它們保留其記憶體佈局

[參考資料]

  • 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++ 文件 關於 Union 宣告
English Deutsch 日本語 한국어 中文(简体) 中文(繁體)