Union 宣告
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 起) |
[關鍵字]
[註解]
關於 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 宣告
|