(自定义类型)联合体union(共用体)

联合体的声明

像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体

 //联合类型的声明 
union U {
	char i;
	int j;
};
int main()
{
//联合类型的定义
	union U u;
	return 0;
}

联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

联合体共用一块空间
代码1:

union U {
	char i;
	int j;
};
int main()
{
	union U u = {0};
	printf("%p\n", &(u.i));
	printf("%p\n", &(u.j));
	printf("%p\n", &u);
	return 0;
}

输出结果为
在这里插入图片描述
三个输出的结果都是相同的地址。

代码2:

union U {
	char i;
	int j;
};
int main()
{
	union U u = { 0 };
	printf("%zd\n", sizeof(u));
	return 0;
}

输出结果为4,而一个整型变量的大小就是4。

代码3:

union U {
	char i;
	int j;
};
int main()
{
	union U u = { 0 };
	u.j = 0x11223344;
	u.i = 0x55;
	printf("%x\n", u.j);
	return 0;
}

输出结果为11223355;说明我们赋值的44被修改了

什么原因导致上面三种情况出现了呢?

我们调试可以发现联合体的 j 确实赋值了相对应的值
在这里插入图片描述
因为是小端存储,所以在低地址,当我们继续向下调试的时候就会发现44被改为55,说明联合体的 i 存储在44的位置。
这也同时说明了他们共用一个地址,共用存储空间,这也解释了为什么刚刚创建的联合体大小是4了。

我们仔细分析就可以画出,u的内存布局图。
在这里插入图片描述
i代表刚刚的整型j,c代表刚刚的字符型i,un是刚刚的结构体。

联合体大小的计算

联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

第二个规则要结合代码理解,比如:

union Un1 {
	char c[5];
	int i;
};
union Un2 {
	short c[7];
	int i;
};

上述代码Un1中 c 的最大对齐数应该是他的成员类型的对齐数,就是1,默认是8,那么取1。
i 的最大对齐数是4,默认是8,那么取4。
那么联合体的最大对齐数就是4,但是char c[5] 占5个字节的空间。这就是第二个规则的情况,最大成员大小是5,不是最大对齐数 4 的整数倍。所以要取最大对齐数的整数倍的大小的内存空间,就是 8 。

以同样的方法分析第二个联合体Un2的大小就是,最大对齐数是4,最大成员大小是14,所以最终的空间大小是16。
在这里插入图片描述

联合体使用场景

很简单的可以看出,联合体和结构体相比是大大节省了内存空间的。但是他的弊端也很明显,就是使用一个其中一个成员,其他成员的值可能也会被改变。
那么使用时就要注意,使用一个成员的时候不能在使用其他成员。

比如下面的场景:

我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、页数
杯⼦:设计
衬衫:设计、可选颜色、可选尺寸

如果我们使用结构体的话

struct gift_list
{
	//公共属性
	int stock_number;//	库存量
	double price; //定价
	int item_type;//商品类型

	//特殊属性
	char title[20];//书名
	char author[20];//作者
	int num_pages;//页数
	char design[30];//设计
	int colors;//颜色
	int sizes;//尺寸
};

实设计的很简单,用起来也方便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常用的。比如:

商品是图书,就不需要design、colors、sizes。

所以我们就可以把公共属性单独写出来,剩余属于各种商品本身的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。

struct gift_list
{
    int stock_number;// 库存量
    double price; //定价
    int item_type;//商品类型
    union {
            struct
            {
                char title[20];//书名
                char author[20];//作者
                int num_pages;//页数
            }book;
            struct
            {
                char design[30];//设计
            }mug;
            struct
            {
                char design[30];//设计
                int colors;//颜⾊
                int sizes;// 尺⼨
            }shirt;//声明了三个匿名结构体
    }item;
};

我们同样可以使用联合体来判断机器的大小端
比如最开始的代码,char类型存在首地址处,整型类型的低地址存在低位还是高位就看机器的大小端。那么我们给整型赋值1,读取char的值就好了。如果char是1,那么就是小端,如果是0,那么就是大端。


int check_sys()
{
	union
	{
		char c;
		int i;
	}u//匿名联合体
	u.i = 1;
	return u.c;
}
int main()
{
	if(check_sys() == 1)
		printf("小端");
	else
		printf("大端");
	return 0;
}
  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值