C 参考手册
- C 语言
- C 的历史
- 基本概念
- 表达式
- 声明
- 初始化
- 函数
- 语句
- 静态断言
- 字符常量
- 函数声明
- 函数定义
- 转义序列
- 翻译阶段
- 标识符
- 作用域
- 生存期
- 查找与命名空间
- ASCII 码表
- 类型
- 遵从性
- 算术类型
- restrict 类型限定符
- 类型
- 对象与对齐
- 主函数
- 未定义行为
- 内存模型
- if 语句
- switch 语句
- for 循环
- while 循环
- do-while 循环
- continue语句
- break 语句
- goto语句
- return 语句
- 值类别
- 求值顺序
- 整数常量
- 浮点常量
- 字符串字面量
- 复合字面量
- 常量表达式
- 隐式转换
- 成员访问运算符
- 逻辑运算符
- 比较运算符
- 算术运算符
- 赋值运算符
- 自增/自减运算符
- 其他运算符
- sizeof 运算符
- _Alignof 运算符
- 转型运算符
- C 运算符优先级
- 泛型选择
- 标量初始化
- 数组初始化
- 结构体与联合体初始化
- 指针声明
- 数组声明
- 枚举
- 存储类指定符
- const 类型限定符
- volatile 类型限定符
- 结构体声明
- 联合体声明
- 位域
- _Alignas
- typedef 声明
- 原子类型
- 外部及试探性定义
- inline 函数指定符
- _Noreturn 函数指定符
- 变长参数
- 内联汇编
- 可分析性
- 替用运算符及记号
- C 关键词
- 预处理器
- C 标准库头文件
- 类型支持
- 程序支持工具
- 变参数函数
- 错误处理
- 动态内存管理
- 日期和时间工具
- 字符串库
- 算法
- 数值
- 文件输入/输出
- 本地化支持
- 原子操作库
- 线程支持库
- 实验性 C 标准库
- 有用的资源
- 符号索引
- 注释
联合体声明
联合体是由一序列的成员所组成的类型,成员的存储重叠(与结构体相反,结构体是由一序列的成员所构成的类型,成员的存储以顺序分配)。在任一时刻,最多能在联合体中存储其一个成员的值。
联合体的类型指定符与结构体 (struct
) 类型指定符相同,只是所用的关键词有别。
语法
union name(可选) { struct-declaration-list }
|
(1) | ||||||||
union name
|
(2) | ||||||||
name | - | 正在定义的联合体名称 |
struct-declaration-list | - | 任意数量的变量声明、位域声明和静态断言声明。不允许不完整类型的成员和函数类型的成员。 |
解释
联合体只大到足以保有其最大成员(亦可能添加额外的尾随填充字节)。其他成员被分配于与该最大成员一部分相同的字节中。
能转型指向联合体的指针为指向它每个成员的指针(若联合体拥有位域成员,则能转型指向联合体的指针为指向位域底层类型的指针)。类似地,指向结构体任何成员的指针都能被转型为指向整个结构体的指针。
若用于访问内容的联合体成员不同于上次用于存储值的成员,则转译被存储值的对象表示为新类型的对象表示(这被称为类型双关)。若新类型的大小大于上次写入的类型大小,则多出的字节内容是未指定的(而且可以是陷阱表示)。
类似结构体,类型为不带 name 的联合体的无名联合体成员被称为匿名联合体。每个匿名联合体的成员被认为是外围结构体或联合体的成员。若外围结构体或联合体亦为匿名,则递归调用此规则。 struct v { union { // 匿名联合体 struct { int i, j; }; // 匿名结构体 struct { long k, l; } w; }; int m; } v1; v1.i = 2; // 合法 v1.k = 3; // 非法:内层结构体不是匿名的 v1.w.k = 5; // 合法 类似结构体,若不以任何具名成员(包含经由匿名嵌套结构体或联合体获得的成员)定义联合体,则程序行为未定义。 |
(C11 起) |
关键词
注意
关于结构体和联合体初始化的规则,见结构体初始化。
示例
运行此代码
#include <stdio.h> #include <stdint.h> #include <assert.h> int main(void) { union S { uint32_t u32; uint16_t u16[2]; uint8_t u8; } s = {0x12345678}; // s.u32 现为活跃成员 printf("Union S has size %zu and holds %x\n", sizeof s, s.u32); s.u16[0] = 0x0011; // s.u16 现为活跃成员 // 从 s.u32 或 s.u8 的读取转译对象表示 // printf("s.u8 is now %x\n", s.u8); // 未指定,典型结果是 11 或 00 // printf("s.u32 is now %x\n", s.u32); // 未指定,典型结果是 12340011 或 00115678 // 指向联合体所有成员的指针彼此间比较相等,也与指向联合体的指针比较相等 assert((uint8_t*)&s == &s.u8); // 此联合体拥有尾随的 3 个填充字节 union pad { char c[5]; // 占据 5 字节 float f; // 占据 4 字节,隐含对齐 4 } p = {.f = 1.23}; // 大小为 8 以满足 float 的对齐 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
如同每个成员都是联合体的仅有成员一般分配每个成员,这是上例中 s.u8
为 s.u32
首字节别名的原因。
引用
- C11 standard (ISO/IEC 9899:2011):
- 6.7.2.1 Structure and union specifiers (p: 112-117)
- C99 standard (ISO/IEC 9899:1999):
- 6.7.2.1 Structure and union specifiers (p: 101-104)
- C89/C90 standard (ISO/IEC 9899:1990):
- 3.5.2.1 Structure and union specifiers