目录
联合也是一种特殊的自定义类型。由多个不同类型的数据成员组成的复合数据类型。
这种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间,所以联合也叫:共用体。
定义一个联合类型的形式如下:
union 联合名
{
成员列表
};
成员列表中含有若干成员,成员的一般形式为: 类型说明符 成员名
成员名的命名应符合标识符的规定。
- #include <stdio.h>
-
- //联合类型的声明
- union Un
- {
- char c;
- int i;
- }un2; //声明的同时并创建un2
-
- union Un un3;//先声明再创建un3 (全局变量)
-
- int main()
- {
- //联合变量的定义
- union Un un1 = { 0 };//先声明再创建un1并初始化 (局部变量)
-
- return 0;
- }
我们运行下面一段代码:
- #include
-
- union Un
- {
- char c;
- int i;
- };
- int main()
- {
- union Un un = { 0 };
-
- printf("%d\n", sizeof(un));//计算联合体的大小
-
- return 0;
- }
运行结果如下:
为什么运行结果为4呢?
那我们就要引入联合体的特点了。
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
由于联合体的所有成员共用同一空间,改变其中一个成员的值可能会影响到其他成员的值,因此联合体中的成员不能同时存在,只适合在某一时间只使用其中单个成员时使用。
就像共享自行车,共享状态,但只能一个人骑,你骑我不骑,我骑你不骑。
例如:
- #include <stdio.h>
-
- union Un
- {
- char c;
- int i;
- };
-
- int main()
- {
- union Un un = { 0 };
-
- un.i = 0x11223344;
- un.c = 0x00;
-
- printf("%x\n", un.i);
- return 0;
- }
调试结果如下:
我们发现运行到c的时候a跟着改变了,将a的第4个字节的内容修改为00了。
先改变的是低地址处的数据(这里是小端存放)。
由此可以发现:联合体的成员是共用一块内存空间的。
- 联合的大小至少是最大成员的大小。
- 联合体在计算大小的时候也存在内存对齐。当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
例:
- #include <stdio.h>
-
- union Un1
- {
- char c[5]; //1 8 1
- //看类型,相当于5个char放在这里,所以自身对齐数为1,默认对齐数为8
- int i; //4 8 4
-
- };
-
- int main()
- {
- printf("%d\n", sizeof(union Un1));//输出8
-
- return 0;
- }
分析:
1、创建一个char类型数组,大小为5个字节,这里相当于5个char,自身对齐数为1,默认对齐数为8,所以对齐数为1。
2、int类型的i自身大小为4个字节,默认对齐数为8,自身对齐数为4,所以对齐数为4。
i和c中最大的对齐数为4,而最大成员大小是数组c(5个字节),5不是4的倍数,对齐规则要求:对齐到最大对齐数(4)的整数倍,所以输出8。
3、虽然共开辟了8个字节,但是只用了5个字节,剩余3个字节没有用。
注意
下图中这两种写法并不等价,这样写是为了方便理解对齐数那里。
第一个arr占用5个字节(共用5个字节),第二个占用1个字节大小(共用1个字节)
例子:
- union Un1
- {
- char c[5];
- int i;
- };
-
- union Un2
- {
- char c1;
- char c2;
- char c3;
- char c4;
- char c5;
-
- int i;
- };
-
- int main()
- {
- printf("%d\n", sizeof(union Un1));//输出8
- printf("%d\n", sizeof(union Un2));//输出4
-
- return 0;
- }
可以通过联合体,可以在不使用额外内存的情况下,判断计算机是大端存储还是小端存储。
代码如下:
- #include
-
- int check_sys()
- {
- union
- {
- int i;
- char c;
- }un;
- un.i = 1;
- return un.c; //返回1是小端,返回0是大端
- }
-
- int main()
- {
- int ret = check_sys();
- if (ret == 1)
- {
- printf("小端\n");
- }
- else
- {
- printf("大端\n");
- }
- }
分析如下:
1、节省空间:
联合体可以最大程度地节省内存,特别是当有多个变量是同一类型的时候。
2、数据类型之间的转换:
联合体可以用于在不同的数据类型之间转换。
联合体的数据之间的转换是指将联合体的一个成员转换为另一个成员的过程。
数据之间的转换可以通过强制类型转换或直接访问成员来实现。
1、不安全:
联合体不提供任何形式的数据隔离,这意味着一个变量可以覆盖另一个变量的数据。所以在访问联合体成员时,需要保证访问的成员与最后一次赋值的成员类型相同,否则可能会出现数据错误或不可预期的结果。
2、可移植性问题:
不是所有的系统对联合体中的对齐做出相同的保证,这可能导致在一个系统上运行正常的代码在另一个系统上出现问题。