一、联合(共用体)定义
联合是一种特殊的自定义类型,该种类型定义的变量也包含一系列的成员,特征是这些成员共用同一块空间,所以联合体也被称为共用体。
代码如下(示例):
#include<stdio.h>
union Un//联合类型的声明,union是联合体关键字
{
char c;//1字节
int i;//4字节
};
int main()
{
union Un u = {0};
printf("%d\n", sizeof(u));
printf("%p\n", &u);
printf("%p\n", &(u.c));//u.c表示联合体的成员c,该引用方法类似结构体
printf("%p\n", &(u.i));
}
运行结果:
分析:
由 sizeof(u) 我们知道这个联合体总计占4个字节,而联合体成员 i 是 int 类型的,它占了4个字节,另外一个 c 是 char 类型占了1个字节,两个一起占了4个字节。说明 c 和 i 必然有一处是共用一块空间的,再者有 u 本身和它的两个成员是一个地址如上图 003EFA80,说明首地址是重合的,简易示图如下:
由于共用空间这种特点就导致了,你改变 c ,i 也会随之改变。这里和结构体是完全不一样的,结构体成员相互独立,但联合体不一样,改变一个其他的也会跟着发生改变。所以这里,在同一时间,你只能使用一个联合体成员,你使用 c 就不要用 i,因为你 c 改变的时候,一定会影响到你i的使用,程序非常容易出问题。
二、联合的特点及运用
联合的成员是共用一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合)
我们再来看看联合体在解决判断内存存储是大端存储还是小端存储的优势:
代码如下(示例):
union U
{
char c;
int i;
}u;//联合体变量创建方法类比结构体
int main()
{
u.i = 1; //0x 00 00 00 01(变量i为int类型,有四个字节,32bit)
/* 低地址----------------------------------------------------->高地址
hex:01 00 00 00 bin:0000 0001 0000 0000 0000 0000 0000 0000 小端存储 低位放低地址
hex:00 00 00 01 bin:0000 0000 0000 0000 0000 0000 0000 0001 大端存储 低位放高地址
*/
//变量c为char类型,只有一个字节,取前8bit即可
if (u.c == 1) //即u.c = 0000 0001
{
printf("小端");
}
else
{
printf("大端");
}
}
运行结果:
分析:
由于 i 和 c 是共用一块内存,我们创建了 i 之后只要判断 1 是在高地址还是低地址即可。又因为 c 是和 i 是一个地址,所以只要判断 c 里面放的是 1 还是 0 即可,非常的方便。(由于我使用的电脑处理器为Intel处理器,因为 Intel 处理器一般都是小端模式,所以此时程序的输出结果为:小端。)
三、联合的大小计算
在计算联合体大小之前我们必须知道两个知识点:
- 联合的大小至少是最大成员的大小
- 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
举例说明:
#include<stdio.h>
union Un1
{
char c[5];//1个char类型占1字节,5个占5字节
int i;//4字节
};
union Un2
{
short c[7];//1个short类型占2字节,7个占14字节
int i;//4字节
};
int main()
{
printf("%d\n", sizeof(union Un1));//打印8
printf("%d\n", sizeof(union Un2));//打印16
}
运行结果:
8 16
分析:
- Un1:char 创建一个大小为 5 的数组和放 5 个char类型的是一样道理,对齐数仍然是 1, int 类型的 i 自身大小 4 字节,对齐数是 4 。i 和 c 两个最大的对齐数是 4,而最大成员大小是数组 c(5个字节),5 不是 4 的倍数,我们需要对齐到最大对齐数的整数倍,也就是 8(从 5 到 8 会浪费 3 个字节空间)。
- Un2:short 创建的 c 数组,我们同上可知其 c 对齐数是 2 ,i 对齐数是4,最大对齐数为4。最大成员大小也就是 c 数组大小为 14 ,14 并不是最大对齐数 4 的整数倍,14 往上对齐到 16, 16 是 4 的整数倍。