一. 什么是共同体?
共同体(Union)是C语言中一种特殊的数据结构,它的所有成员共享同一块内存空间。与结构体(Struct)不同,结构体的每个成员有独立的内存空间,而共同体的所有成员覆盖同一段内存。这意味着,共同体在任意时刻只能存储其中一个成员的值。
二. 为什么需要共同体?
共同体的主要目的是节省内存,适用于以下场景:
- 需要存储不同类型的数据,但每次只用其中一种。
- 处理硬件寄存器(如嵌入式开发)。
- 解析网络协议中的二进制数据。
- 需要灵活操作内存(如底层开发)。
三. 如何使用共同体?
1.定义共同体
使用 union
关键字定义共同体,格式如下:
union UnionName {
数据类型 成员1;
数据类型 成员2;
...
};
示例:定义一个可以存储整数、浮点数或字符串的共同体
#include <stdio.h>
#include <string.h>
// 定义共同体
union Data {
int i; // 整数
float f; // 浮点数
char str[20]; // 字符串
};
2.声明变量
共同体变量的声明方式与结构体类似:
union Data data1, data2; // 声明两个共同体变量
3.赋值与访问
共同体的成员通过点运算符(.
)访问,但每次只能给一个成员赋值,新值会覆盖旧值。
示例:赋值与访问
int main() {
union Data data;
// 存储整数
data.i = 10;
printf("data.i: %d\n", data.i); // 输出: 10
// 存储浮点数(覆盖之前的整数)
data.f = 3.14;
printf("data.f: %.2f\n", data.f); // 输出: 3.14
// 存储字符串(覆盖之前的浮点数)
strcpy(data.str, "Hello");
printf("data.str: %s\n", data.str); // 输出: Hello
return 0;
}
4.内存大小
共同体的大小等于其最大成员的大小。例如:
printf("Size of union: %lu bytes\n", sizeof(union Data));
// 输出: 20 bytes(因为 char str[20] 占用 20 字节)
四、代码示例详解
完整示例:共同体的定义与使用
#include <stdio.h>
#include <string.h>
// 定义共同体
union Money {
int moneyi; // 整数
double moneyd; // 双精度浮点数
char moneystr[100]; // 字符串
};
int main() {
union Money money;
// 存储整数
money.moneyi = 100;
printf("整数: %d\n", money.moneyi);
// 存储双精度浮点数(覆盖之前的整数)
money.moneyd = 100.111;
printf("浮点数: %.3lf\n", money.moneyd);
// 存储字符串(覆盖之前的浮点数)
strcpy(money.moneystr, "100万");
printf("字符串: %s\n", money.moneystr);
// 打印内存地址(验证共享内存)
printf("moneyi 地址: %p\n", &money.moneyi);
printf("moneyd 地址: %p\n", &money.moneyd);
printf("moneystr 地址: %p\n", &money.moneystr);
// 打印共同体大小
printf("共同体大小: %lu 字节\n", sizeof(money));
return 0;
}
运行结果:
整数: 100
浮点数: 100.111
字符串: 100万
moneyi 地址: 0x7ffee4b3c8a0
moneyd 地址: 0x7ffee4b3c8a0
moneystr 地址: 0x7ffee4b3c8a0
共同体大小: 104 字节
关键点:
- 所有成员的内存地址相同,说明它们共享同一块内存。
- 共享内存的大小由最大成员决定(
char moneystr[100]
占 100 字节,加上对齐后总大小为 104 字节)。
⚠️ 重要警告:
同一时刻只能使用一个成员!修改一个成员会覆盖其他成员的值。
五. 注意事项
- 数据覆盖:每次赋值会覆盖之前的值,因此要确保访问的是最后一次赋值的成员。
- 初始化:共同体变量在定义时只能初始化第一个成员。
- 类型安全:使用共同体时需明确当前存储的是哪种类型的数据,否则可能导致未定义行为。
- 应用场景:适合需要灵活存储不同类型数据且内存有限的场景,如嵌入式系统或网络协议解析。
六、特点
#include <stdio.h>
#include <string.h>
union UnionDemo {
int num;
float f;
char text[6];
};
int main() {
union UnionDemo u;
printf("共用体大小:%zu 字节\n", sizeof(u));
// 1. 存入整数并读取
u.num = 0x12345678;
printf("存入整数后:num=0x%X\n", u.num); // 正确访问方式
// 2. 存入浮点数并读取
u.f = 3.14f;
printf("存入浮点数后:f=%.2f\n", u.f); // 正确访问方式
// 3. 存入字符串并读取
strcpy_s(u.text, sizeof(u.text), "Hi"); // 或者使用 strncpy
printf("存入字符串后:text=%s\n", u.text); // 正确访问方式
// 演示错误访问方式(不要这样做)
printf("错误访问示例:num=0x%X, f=%.2f\n", u.num, u.f);
return 0;
}
七. 总结
共同体是C语言中一种强大的工具,通过共享内存实现高效的数据存储。虽然它的使用需要谨慎(因为数据会被覆盖),但在特定场景下(如硬件编程、数据解析)能显著优化内存使用。掌握共同体的定义、使用方法和注意事项,能帮助你编写更高效的C程序!