联合体
联合体(Union)是C语言中一种特殊的用户自定义数据类型,它允许在同一内存位置存储不同的数据类型。与结构体不同,联合体的所有成员共享同一块内存空间,这意味着任何时候只能使用联合体的一个成员。
结构体(struct)中的每个成员都有自己的内存空间,而联合体(union)的所有成员共享同一块内存空间。这是两者最本质的区别。
cpp
// 结构体示例
struct Example {
int i; // 4字节
float f; // 4字节
char c; // 1字节
}; // 总大小约为12字节(考虑内存对齐)
// 联合体示例
union Example {
int i; // 4字节
float f; // 4字节
char c; // 1字节
}; // 总大小为4字节(最大成员的大小)

联合体的大小等于其最大成员的大小 (可能会因内存对齐而增加)。所有成员的起始地址都相同,它们相互覆盖。
cpp
union 联合体标签名 {
成员类型1 成员名1;
成员类型2 成员名2;
// ...更多成员
};
声明
cpp
union Data data; // 声明一个Data类型的联合体变量
union Data {
int i;
float f;
char str[20];
} data1, data2;
初始化
cpp
union Data data = {10}; // 初始化第一个成员i为10
union Data data = {.f = 3.14}; // 初始化成员f为3.14
联合体成员的访问
使用点运算符访问
cpp
#include <stdio.h>
#include <string.h>
int main() {
union Data {
int i;
float f;
char str[20];
};
union Data data;
// 给联合体成员赋值
data.i = 10;
printf("data.i: %d\n", data.i);
// 给另一个成员赋值(会覆盖之前的值)
data.f = 220.5;
printf("data.f: %.1f\n", data.f);
// 此时data.i的值已经被覆盖,不再是10
printf("data.i: %d\n", data.i); // 输出一个"奇怪"的值
// 给字符数组成员赋值
strcpy(data.str, "C语言");
printf("data.str: %s\n", data.str);
// 此时data.i和data.f的值都被覆盖
return 0;
}
使用指针访问
cpp
#include <stdio.h>
int main() {
union Data {
int i;
float f;
char str[20];
};
union Data data;
union Data *ptr = &data; // 定义联合体指针并指向data
// 通过指针给联合体成员赋值
ptr->i = 10;
printf("ptr->i: %d\n", ptr->i);
// 通过指针给另一个成员赋值
ptr->f = 220.5;
printf("ptr->f: %.1f\n", ptr->f);
return 0;
}
联合体内存访问
cpp
#include <stdio.h>
int main() {
union Example {
char c; // 1字节
short s; // 2字节
int i; // 4字节
double d; // 8字节
};
union Example ex;
printf("联合体大小: %lu字节\n", sizeof(union Example)); // 通常输出8
printf("c的地址: %p\n", &ex.c);
printf("s的地址: %p\n", &ex.s);
printf("i的地址: %p\n", &ex.i);
printf("d的地址: %p\n", &ex.d);
// 所有成员的地址都相同
return 0;
}

注意:
使用联合体时,最重要的是要记住任何时候只有一个成员的值是有效的。给一个成员赋值会覆盖其他成员的值。
cpp
union Data {
int i;
float f;
};
union Data data;
data.i = 10;
data.f = 3.14; // 此时data.i的值被覆盖,不再是10
cpp
union {
int i;
float f;
} data;
data.i = 123456;
printf("%f\n", data.f); // 类型不同,不安全。输出一个"奇怪"的浮点数