跳转至

union 共用体

方法速览

任务 方法 口诀
判断行为 所有成员共享同一块内存,同一时刻只有一个成员有效 全家住一间房
求大小 \(\max\)(各成员大小),再对齐到最大成员的对齐值 取最长那根
访问成员 变量用 .,指针用 -> 变量点、指针箭
与 struct 区别 struct 人人一间房(大小 \(\geq\) 成员和),union 全员一间房(大小 = 最大成员) struct 合住、union 拼租

定义与内存布局

union(共用体)是让多个成员共用同一块内存的构造类型:

1
2
3
4
5
6
union Data {
    int num;      // 4 字节
    float value;  // 4 字节
    char symbol;  // 1 字节
};
union Data data;  // 只分配 4 字节(最大成员的大小)

内存布局对照(以 4 字节 union 为例):

成员 占用的字节
num 全部 4 字节
value 全部 4 字节
symbol num第 1 个字节重叠

三条性质:

  • 大小 = 最大成员(再按最大对齐值补齐):sizeof(Data) = 4,不是 \(4+4+1\)
  • 同一时刻只有一个成员有效:给 value 赋值后,num 里读到的是 value 的位串重解释,是垃圾值;
  • 改一个成员,其余成员跟着变化——因为动的是同一块内存。

data.num = 1; data.symbol = 'A'; 之后 data.num 不再是 1——symbol 只覆盖了低 1 个字节,读出来是乱码。

成员访问

与 struct 完全一样:变量用 .,指针用 ->

union Data data;        data.value = 3.14;   // 变量用 .
union Data* p = &data;  p->value = 3.14;     // 指针用 ->

初始化:不带指示符时只能初始化第一个成员union Data d = {42}; 给的是 num。C++11 起可用 union Data d = {.value = 3.14}; 指定成员。

与 struct 的区别

对比项 struct union
内存 每个成员各占一块 所有成员共享一块
大小 \(\geq\) 成员大小之和(对齐填充) = 最大成员(对齐补齐)
有效成员 全部同时有效 同一时刻只有一个
用途 把不同类型打包在一起(点坐标) 同一块内存的多种解读(省空间/拆字节)

struct S { int i; double d; };   // 4 + 4(填充) + 8 = 16 字节
union  U { int i; double d; };   // max(4, 8)      = 8 字节

union 的两个经典用途:

  • 拆字节:把 floatchar[4] 放进 union,写 float 读 char 数组,逐字节取出;
  • 判大小端u.num = 1; u.byte[0] == 1 说明低字节放在低地址(小端)。

练习题目

练习 1 · 成员访问(变量)

题目

union Data { int num; float value; char symbol; }; union Data data; 要修改 value 成员存 3.14,正确写法是( )

  • A. data.value = 3.14;
  • B. value.data = 3.14;
  • C. data->value = 3.14;
  • D. value->data = 3.14;
答案与解析

答案:A

data 是变量,用 .data->value 是指针的写法,data 不是指针。

干扰项思路:B/D 把成员名与变量名写反;C 混淆了 .->

练习 2 · 成员访问(指针)

题目

union Data* p; 要通过 p 修改 num 成员,正确写法是( )

  • A. p.num = 5;
  • B. *p.num = 5;
  • C. num->p = 5;
  • D. p->num = 5;
答案与解析

答案:D

指针用 ->p.num 语法错误(p 不是结构体变量);*p.num 因优先级解析为 *(p.num),同样错误。

练习 3 · 大小 = 最大成员

题目

union U { char c; int i; };sizeof(U) 是( )

  • A. \(1\)
  • B. \(5\)
  • C. \(4\)
  • D. \(8\)
答案与解析

答案:C

union 大小 = 最大成员 = int 的 4 字节。

干扰项思路:B 想成了 struct 的“成员相加”。

练习 4 · 大小与对齐

题目

union U { char c[9]; int i; };sizeof(U) 是( )

  • A. \(9\)
  • B. \(12\)
  • C. \(13\)
  • D. \(4\)
答案与解析

答案:B

最大成员 char c[9] 占 9 字节,但对齐值是 int 的 4 → 补齐到 4 的倍数 = 12。

干扰项思路:A 忘了对齐补齐。

练习 5 · union 含 double

题目

union U { char c; int i; double d; };sizeof(U) 是( )

  • A. \(13\)
  • B. \(16\)
  • C. \(8\)
  • D. \(4\)
答案与解析

答案:C

最大成员 double = 8 字节,char、int 都比它小 → 8。

干扰项思路:A 成员相加;B 与 struct 的对齐算法混淆。

练习 6 · struct 与 union 大小对比

题目

struct S { int i; double d; };union U { int i; double d; }; 的 sizeof 分别是( )

  • A. \(16\)\(8\)
  • B. \(12\)\(8\)
  • C. \(8\)\(8\)
  • D. \(16\)\(12\)
答案与解析

答案:A

struct:\(4 + 4\)(对齐填充)\(+ 8 = 16\);union:\(\max(4,8) = 8\)

练习 7 · struct 相加、union 取最大

题目

struct S { char a; int b; };union U { char a; int b; }; 的 sizeof 分别是( )

  • A. \(5\)\(4\)
  • B. \(8\)\(4\)
  • C. \(8\)\(5\)
  • D. \(4\)\(4\)
答案与解析

答案:B

struct:char 后填充 3 字节对齐 int,共 8;union:\(\max(1,4) = 4\)

干扰项思路:A 是“相加 vs 取最大”的裸算,忘了对齐。

练习 8 · 共享内存的直接后果

题目

union U { int i; char c; } u; u.i = 0x41424344; u.c = 'A'; 之后 u.i 的值(小端机)是( )

  • A. 不变,仍为 \(0x41424344\)
  • B. 未定义,程序崩溃
  • C. 变为 \(0\)
  • D. 低字节被覆盖,变为 \(0x41424341\)
答案与解析

答案:D

ci低字节重叠:写入 'A'\(0x41\))只改低 8 位,高 3 字节保留。

干扰项思路:A 忽略“共享内存”;这是 union 最核心的行为。

练习 9 · 同一时刻只有一个有效

题目

关于 union 成员的有效性,正确的是( )

  • A. 所有成员始终同时有效
  • B. 同一时刻只有一个成员的值是有效写入的,其余是同一位串的别的解读
  • C. 只有第一个成员有效
  • D. 只有最后一个定义的成员有效
答案与解析

答案:B

最后一次写入哪个成员,哪个才有效;读其他成员得到的是同一位串按别的类型解读,通常无意义。

练习 10 · 写 A 读 B

题目

union U { int i; float f; } u; u.f = 1.0f; cout << u.i; 的输出是( )

  • A. \(1\)
  • B. \(0\)
  • C. \(1065353216\)
  • D. 编译错误
答案与解析

答案:C

1.0f 的 IEEE 754 位串是 \(0x3F800000\),按 int 解读就是 \(1065353216\)——写 float 读 int,得到的是位串重解释,不是数值转换。

练习 11 · 用途:判大小端

题目

union U { int i; char c[4]; } u; u.i = 1;u.c[0] == 1,说明机器是( )

  • A. 小端序
  • B. 大端序
  • C. 与字节序无关
  • D. 16 位机
答案与解析

答案:A

c[0] 对应最低地址的字节;低地址存着 1(低字节)→ 小端。

练习 12 · 用途:拆 float 字节

题目

要逐字节查看一个 float 的存储位串,最合适的工具是( )

  • A. 把 float 强转成 int
  • B. union { float f; unsigned char b[4]; }
  • C. 用 strlen
  • D. 用 sizeof
答案与解析

答案:B

union 写 float、读字节数组,同一位串两种解读——强转会改变数值(截断),拿不到原始位。

练习 13 · 什么时候选 union

题目

以下场景最适合用 union 的是( )

  • A. 存一个点的横纵坐标 \(x, y\)
  • B. 给函数传多个输出参数
  • C. 存全班同学的成绩列表
  • D. 一种数据包有多种格式,任意时刻只会是其中一种,想省内存
答案与解析

答案:D

互斥使用的多格式共享一块内存是 union 的本职;A、C 要同时保存多个值(B 是传参场景,用引用/指针更合适)。

练习 14 · 什么时候不能用 union

题目

以下场景不能用 union 的是( )

  • A. 判断机器字节序
  • B. 把 float 的 4 个字节逐个取出
  • C. 同时保存学生的学号(int)和年龄(int)
  • D. 同一块内存按需解释成 int 或 unsigned int
答案与解析

答案:C

学号和年龄要同时有效,union 同一时刻只能保一个。

练习 15 · 初始化

题目

union U { int i; char c; }; 执行 U u = {65}; 后( )

  • A. u.i 为 65,是当前有效成员
  • B. u.c 为 'A',是当前有效成员
  • C. 两者同时有效
  • D. 编译错误
答案与解析

答案:A

花括号初始化只初始化第一个成员

干扰项思路:B 位串上 c 确实读到 65,但初始化语义针对的是第一个成员 i

练习 16 · union 作为 struct 成员

题目

struct S { int tag; union { int i; float f; } u; }; 关于 S 的说法正确的是( )

  • A. 语法错误,union 不能放进 struct
  • B. 合法,u 的大小是 4 字节
  • C. 合法,u 的大小是 8 字节
  • D. S 的大小等于 tag 与两个 union 成员之和
答案与解析

答案:B

union 可作 struct 成员;内部 union \(\max(4,4) = 4\) 字节,S 共 \(4 + 4 = 8\) 字节。

练习 17 · 匿名 union

题目

struct S { int tag; union { int i; float f; }; };(union 无名,s 是 S 的变量)则访问其中的 int 成员写作( )

  • A. s.u.i
  • B. s::i
  • C. s.i
  • D. union.s.i
答案与解析

答案:C

匿名 union 的成员直接提升到外层作用域s.is.f 直接访问。

练习 18 · union 里放数组

题目

union U { short s[4]; int i; };sizeof(U) 是( )

  • A. \(4\)
  • B. \(2\)
  • C. \(12\)
  • D. \(8\)
答案与解析

答案:D

short s[4]\(4\times2 = 8\) 字节 > int 的 4 → 8。

练习 19 · typedef union

题目

typedef union { int i; double d; } Data; 之后定义变量应写( )

  • A. union Data d;
  • B. Data d;
  • C. struct Data d;
  • D. Data union d;
答案与解析

答案:B

typedef 后 Data 就是类型名,直接用;union Data 反而错误(typedef 出来的名字前不再加 union 关键字)。

练习 20 · union 的类型身份

题目

关于 union 的说法,错误的是( )

  • A. union 是构造类型,不是基本数据类型
  • B. union 的成员默认访问权限是 public
  • C. 同类型 union 变量之间可以直接赋值
  • D. union 的大小等于所有成员大小之和
答案与解析

答案:D

union 大小 = 最大成员(对齐后)——成员之和是 struct 的算法。

练习 21 · union 赋值

题目

Data a, b; a.num = 7; b = a; 之后 b.num 的值( )

  • A. \(7\)
  • B. \(0\)
  • C. 未定义
  • D. 编译错误
答案与解析

答案:A

同类型 union 变量可整体赋值,整块内存拷贝——当前有效成员跟着过去。

练习 22 · 修改一个成员(半字节级)

题目

union U { int i; short s; } u; u.i = 0xAAAABBBB; u.s = 0; 之后 u.i 是(小端机)( )

  • A. \(0xAAAA0000\)
  • B. \(0xAAAABBBB\)
  • C. \(0x0000BBBB\)
  • D. \(0\)
答案与解析

答案:A

si低 16 位重叠:写入 0 只清低半,高半 \(0xAAAA\) 保留 → \(0xAAAA0000\)

干扰项思路:B 忽略重叠;D 多清了高半;C 清错了一半。

练习 23 · 三成员大小

题目

union U { char c; short s; int i; }; 在 64 位环境下 sizeof(U) 是( )

  • A. \(1\)
  • B. \(2\)
  • C. \(4\)
  • D. \(7\)
答案与解析

答案:C

\(\max(1, 2, 4) = 4\)

干扰项思路:D 成员相加。

练习 24 · 与 struct 的语义差

题目

同样写 x.i = 1; x.d = 2.0;(i 是 int,d 是 double),对 struct 变量与 union 变量,结果分别是( )

  • A. struct:两者都有效;union:只有 d 有效,i 被破坏
  • B. 都有效
  • C. 都只剩一个有效
  • D. union 里 i 仍然有效
答案与解析

答案:A

struct 各住各的房间互不干扰;union 一间房,后写的破坏先写的。

练习 25 · 综合辨析

题目

下列说法正确的是( )

  • A. union 变量既可以用 . 也可以用 -> 访问成员
  • B. sizeof(union) 不可能小于其中任何一个成员
  • C. union 的所有成员可以同时有效
  • D. union 的大小由第一个成员决定
答案与解析

答案:B

union 至少要装下最大的成员:sizeof ≥ 每个成员的大小。A:. 给变量、-> 给指针;C:只有一个有效;D:由最大成员决定。

练习 26 · 空间节省估算

题目

某记录要存“要么一个 int 编号、要么一个 8 字节坐标”,共 1 万条。用 union(8 字节)比用 struct(int + double,对齐后 16 字节)大约节省( )

  • A. \(40\) KB
  • B. \(80\) KB
  • C. \(160\) KB
  • D. 不节省
答案与解析

答案:B

每条省 \(16 - 8 = 8\) 字节:\(10^4 \times 8 = 8\times10^4\) 字节 \(\approx 80\) KB。

历年真题

2023 年 · 第 3 题

题目

阅读下述代码,请问修改 datavalue 成员以存储 3.14,正确的方式是( )。

1
2
3
4
5
6
union Data {
    int num;
    float value;
    char symbol;
};
union Data data;
  • A. data.value = 3.14;
  • B. value.data = 3.14;
  • C. data->value = 3.14;
  • D. value->data = 3.14;
答案与解析

答案:A

data 是 union 变量,成员访问用 .-> 只用于指针(union Data* p = &data; p->value = 3.14;)。B/D 成员名与变量名写反。

易错小结

  • union 大小 = 最大成员(对齐补齐),不是成员之和——成员之和是 struct 的算法;
  • 同一时刻只有一个成员有效:写 A 读 B 得到的是位串重解释(写 1.0f 读 int 出 1065353216);
  • 变量用 .、指针用 ->,union 与 struct 规则相同;
  • 花括号初始化只初始化第一个成员
  • 需要“同时有效”的多个值必须用 struct;union 只适合互斥解读、省空间、拆字节、判大小端。