什么是共用体?
共用体是一种特殊的数据类型,它允许您在不同的时间(不是同时)存储不同类型的数据。它的所有成员共享同一块内存空间。
核心思想: 共用体中所有成员的起始地址都是相同的。这意味着,修改一个成员的值,会直接影响其他成员的值。
如何定义共用体?
使用 union 关键字来定义,语法与结构体 struct 非常相似。
c
union 共用体名称 {
数据类型 成员1;
数据类型 成员2;
// ... 更多成员
};
示例:定义一个共用体
c
union Data {
int i; // 4字节(通常)
float f; // 4字节(通常)
char str[20]; // 20字节
};
在这个例子中:
union Data类型的一个变量将占用 20个字节 的内存空间(因为它的最大成员str[20]是20字节)。- 这20个字节被三个成员
i,f,str共享。
如何使用共用体?
与结构体一样,使用成员运算符 . 来访问成员。
c
#include <stdio.h>
#include <string.h>
union Data {
int i;
float f;
char str[20];
};
int main() {
union Data data; // 声明一个共用体变量
// 使用整数成员
data.i = 10;
printf("data.i : %d\n", data.i); // 输出:data.i : 10
// 使用浮点数成员
data.f = 220.5;
printf("data.f : %.2f\n", data.f); // 输出:data.f : 220.50
// 注意:此时 data.i 的值已经被破坏,因为它和 data.f 共享内存
// 使用字符数组成员
strcpy(data.str, "C Programming");
printf("data.str : %s\n", data.str); // 输出:data.str : C Programming
// 注意:此时 data.i 和 data.f 的值都已被破坏
return 0;
}
关键观察:
当你给 data.f 赋值后,之前存储在 data.i 中的值就变得无意义了。同样,当你给 data.str 赋值后,data.f 的值也被破坏了。因为它们都使用同一块内存。
共用体 vs. 结构体
为了加深理解,我们来看一个与结构体的直观对比。
c
#include <stdio.h>
// 结构体
struct MyStruct {
int i;
float f;
char str[20];
};
// 共用体
union MyUnion {
int i;
float f;
char str[20];
};
int main() {
struct MyStruct s;
union MyUnion u;
printf("结构体大小 : %lu 字节\n", sizeof(s));
printf("共用体大小 : %lu 字节\n", sizeof(u));
return 0;
}
输出可能是:
结构体大小 : 28 字节
共用体大小 : 20 字节
为什么?
- 结构体: 每个成员都有自己独立的内存空间。
s.i,s.f,s.str的地址都不同。总大小是所有成员大小之和(可能加上一些对齐填充)。 - 共用体: 所有成员共享同一块内存。总大小由其最大成员 的大小决定(这里是20字节的
str)。
共用体的主要用途
-
节省内存:当你知道一个变量在程序的不同阶段会用于存储不同类型的数据,并且这些数据不会同时需要时,使用共用体可以大幅节省内存。这在嵌入式系统等内存受限的环境中尤其重要。
-
解释同一数据的多种方式 :例如,你可以用一个共用体来将一个4字节的
int数据,按照char数组的方式逐个字节地解析和处理。cunion IntConverter { int number; unsigned char bytes[4]; }; union IntConverter converter; converter.number = 0x12345678; // 现在你可以通过 bytes 数组访问整数的每一个字节 for(int i = 0; i < 4; i++) { printf("Byte %d: 0x%02X\n", i, converter.bytes[i]); } -
实现变体记录:在通信协议或文件格式中,一个数据包可能根据"类型"字段的不同,后面跟着不同类型的数据。共用体可以完美地模拟这种情况。
注意事项(重要!)
-
只能使用一个成员:在某一时刻,只有一个成员是有效的。你最后一次赋值的成员才是那个你可以正确读取的成员。
-
未定义行为:读取一个你没有写入的成员,其结果是未定义的(可能得到垃圾值,也可能导致程序崩溃)。
-
初始化 :只能初始化共用体的第一个成员 。
cunion Data data = {10}; // 正确,初始化 i 为 10 // union Data data = {3.14}; // 错误!不能这样初始化 f
总结
| 特性 | 结构体 | 共用体 |
|---|---|---|
| 关键字 | struct |
union |
| 内存 | 成员内存独立 | 成员内存共享 |
| 总大小 | 所有成员大小之和 + 对齐填充 | 最大成员的大小 + 对齐填充 |
| 用途 | 存储一组相关的、同时存在的数据 | 存储一组互斥的、不同时存在的数据 |
共用体是C语言中"用空间换时间"以及进行底层数据操作的精妙工具。理解并正确使用它,能让你的程序更加高效和灵活。