前言
本章我们来了解C语言中的联合体,它的基本基本使用,内存计算,大小端判断应用与结构体struct的区别等知识点。
什么是联合体
union
(联合体)是C语言(及其衍生语言如C++)中一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。union
的主要特点是其所有成员共享同一段内存空间,这意味着在任何给定时刻,union
只存储其成员中的一个值,且该值是最近一次被赋予的值。
基本用法
union Data {
int i;
char str;
};
union Data data;
在这个例子中,Data
是一个union
类型,它包含了两个成员:一个int
、一个字符char
。然而,这两个成员并不是同时存在的;相反,它们共享同一段内存空间。因此,如果你给data.i
赋值,那么data.str
的值将会变得不可预测,因为它现在包含了int
类型的数据的字节表示。
一般的存储是分开这样存的;
而联合体是共用内存的;
使用示例
#include <stdio.h>
union Data {
int i;
float f;
};
int main() {
union Data data;
// 初始化int成员
data.i = 10;
printf("As int: %d\n", data.i); // 输出:As int: 10
// 现在float成员包含了相同的字节,但可能不是有效的float值
printf("As float (may be garbage): %f\n", data.f); // 输出可能是垃圾值
// 初始化float成员
data.f = 220.5;
printf("As float: %f\n", data.f); // 输出:As float: 220.500000
// 现在int成员包含了相同的字节,但可能不是有效的int值
printf("As int (may be garbage): %d\n", data.i); // 输出可能是垃圾值
return 0;
}
你可以看到当union
的一个成员被赋值时,其他成员的值将变得不可预测,因为它们共享同一段内存空间。
内存大小计算
那么给这个联合体分配的内存要怎么计算呢
1,union
的大小至少是其最大成员的大小。编译器会确保union
有足够的空间来存储其最大的成员。
2,如果最大成员的大小不是最大对齐数的整数倍,则需要将联合体的大小对齐到最大对齐数的整数倍。
union MyUnion {
char c[5];
int i;
};
在大多数编译器中(特别是考虑到默认对齐数),这个联合体的大小和对齐方式会这样计算:
char c[5]
:占用5个字节,但由于是数组,对齐数为1
int i
:在大多数平台上占用4个字节,并需要按4字节对齐。
最大成员是char c[5],5个字节。然而,由于int i 只占用4个字节,如果直接以4字节作为联合体的大小,那么它将小于最大成员的大小。因此,编译器会在char
数组之后填充3个字节的空白,使得整个联合体的大小达到8字节,以大于最大成员。
大小端判断应用
union
类型允许在相同的内存位置存储不同的数据类型。这一特性可以用来判断系统是采用大端(Big-Endian)还是小端(Little-Endian)字节序。
大端字节序指的是数据的高位字节保存在内存的低地址中,而数据的低位字节保存在内存的高地址中;小端字节序则相反,数据的低位字节保存在内存的低地址中,而数据的高位字节保存在内存的高地址中。
下面是一个使用 union
来判断系统字节序(大端或小端)的示例代码:
#include <stdio.h>
union EndianTest {
uint32_t i;
char c[4];
};
int main() {
union EndianTest test;
test.i = 0x01020304; // 初始化一个整数
// 检查第一个字节(即低地址处的字节)
if (test.c[0] == 1) {
printf("Little-Endian\n");
} else if (test.c[0] == 0) {
printf("Big-Endian\n");
} else {
printf("Unknown\n");
}
return 0;
}
将整数 0x01020304
赋值给 i
后,我们检查 c[0]
的值。在小端字节序的系统中,0x01
(即整数的最低有效字节)会被存储在 c[0]
中,因为 c[0]
对应于最低的内存地址。而在大端字节序的系统中,0x04
(即整数的最高有效字节)会被存储在 c[0]
中。
因此,通过检查 c[0]
的值,我们可以判断系统是采用大端还是小端字节序。
与结构体的区别
1. 内存分配
- struct:
struct
中的每个成员都拥有独立的内存空间。一个struct
变量的总长度是其所有成员的长度之和,且通常会根据编译器的内存对齐规则进行适当调整。 - union:
union
中的所有成员共享同一段内存空间。一个union
变量的长度等于其最长成员的长度。在任何时候,union
中只有一个成员的值是有效的。
2. 成员赋值与访问
- struct:对
struct
中的不同成员赋值不会影响到其他成员的值,因为它们的内存空间是分开的。可以通过成员名来访问struct
中的每个成员。 - union:对
union
中的某个成员赋值会覆盖其他成员的值,因为它们共享同一段内存。通常只初始化一个成员,并通过相同的成员名来访问当前有效的成员。
3. 使用场景
- struct:常用于定义复杂的数据结构,如链表节点、学生信息记录等,便于组织和管理数据。每个成员都有独立的存储空间,互不干扰。
- union:适用于节省内存空间,尤其是在需要存储多个可能类型但一次只使用一种类型的数据时。常用于网络协议解析、硬件寄存器访问等场景。
以上就是所有内容啦,如果觉得有用请来个三连支持一下吧~谢谢~