C语言自定义数据类型详解(四)——联合体

好的,接下来我们来学习最后一个自定义数据类型------联合体。

一、什么是联合体:

联合体又叫共用体,用关键字union来进行定义。又因为所有的成员变量共用同一段内存空间(关于这一点,我们不久就会加以验证),所以它是一种比较特殊的自定义类型。

二、联合体的内存布局:

(1)验证联合体成员共用同一块空间:

我们前面已经提到了说联合体它的成员变量都是共用同一段内存空间的,我们可以通过下面这个代码对这一结论加以验证:

cpp 复制代码
#include<stdio.h>
union Uo
{
	int a;
	char i;
};
int main()
{
	union Uo u;
	printf("sizeof(u) == %zd\n", sizeof(u));
	printf("%p\n", &(u.a));
	printf("%p\n", &(u.i));
	return 0;
}

运行效果:

我们发现对于联合体u,它的大小是4Byte,且无论是针对它的成员变量a取地址,还是针对它的成员变量i取地址,它的结果都是一样的。

我们可以进一步做一些事情,我们修改变量a的值,然后来观察成员变量i是否会受影响。因此我们写出下面这个代码:

cpp 复制代码
#include<stdio.h>
union Uo
{
	int a;
	char i;
};
int main()
{
	union Uo u;
	u.a = 0x44332211;
    //%x是以十六进制打印整数:
	printf("0x%x\n", u.a);
	printf("0x%x\n", u.i);
	return 0;
}

运行结果(注意这里的结果你可能和我不一样,因为这和机器是小端字节序,还是大端字节序有关系。而博主现在是小端字节序的机器):

我们发现对联合体中某一个成员变量的值进行修改,也会影响到其他的成员变量。这里又进一步佐证了联合体的成员变量共用同一段内存空间这一事实。

综上,对于联合体变量union Uo u来说,它的内存布局是:


(2)联合体内存大小的计算:

有很多小伙伴在联合体这里会犯一个错误,认为联合体的大小就是最大成员变量的大小。但是其实不然,就比如说下面这个代码场景:

cpp 复制代码
#include<stdio.h>
union Uo
{
	int a;
	char i[5];
};
int main()
{
	union Uo u;
	printf("%zd\n", sizeof(u));
	return 0;
}

运行结果:

所以关于联合体的大小:我们认为联合体的大小至少是最大成员变量的大小。当最大成员变量的大小不是最大对齐数的整数倍时(关于对齐数可以看博主的前面的博客C语言自定义数据类型详解(二)------结构体类型(下)-CSDN博客)需要进行内存对齐。

三、联合体的应用场景:

我们试想这么一个场景:我们要求设计一些数据类型来存储图书布袋衬衫这三个商品的一些属性。那首先分析这三个商品,它们都有各自以下这些属性:

图书:库存量,价格,书名,作者;

布袋:库存量,价格,样式;

衬衫:库存量,价格,颜色,尺寸;

那据此,你可不可以设计下面这样的:

cpp 复制代码
struct book
{
	int _stock;  //库存
	float _price;//价格

	char _bookName[30];//书名
	char _writer[30];  //作者
};
struct bag
{
	int _stock;  //库存
	float _price;//价格

	char _style[30];//样式
};
struct shirt
{
	int _stock;  //库存
	float _price;//价格

	char color[15];//颜色
	size_t _size;  //尺寸
};

但是你有没有觉得这个设计比较冗余,因为库存量和价格都是这些商品共有的属性。这在C++,Java里面可以通过继承的方式来消除这种设计上的冗余,那C语言呢?OK,C语言可以借助联合体设计出下面这个结构体:

cpp 复制代码
#include<stdio.h>
#include<string.h>
struct commodity
{
	int _stock;  //库存
	float _price;//价格
	//这里面都是匿名结构体和匿名联合体哦!
	union
	{
		struct
		{
			char _bookName[30];//书名
			char _writer[30];  //作者
		} _book;
		struct
		{
			char _style[30];//样式
		} _bag;
		struct
		{
			char color[15];//颜色
			size_t _size;  //尺寸
		} _shirt;
	}_item;
};
int main()
{
	struct commodity com;
	//注意这里的_writer是char* const的指针(常量指针),所以不能写作com._item._book._writer = "MoYan";
	strcpy(com._item._book._writer, "MoYan");
	printf("The writer of the book is %s\n", com._item._book._writer);
	return 0;
}

OK,这次的知识分享就到这里了,我们下次再见!

相关推荐
0和1的舞者5 小时前
《Git:从入门到精通(八)——企业级git开发相关内容》
大数据·开发语言·git·搜索引擎·全文检索·软件工程·初学者
liulilittle6 小时前
LwIP协议栈MPA多进程架构
服务器·开发语言·网络·c++·架构·lwip·通信
水淹萌龙6 小时前
玩转 Go 表达式引擎:expr 实战指南
开发语言·后端·golang
艾莉丝努力练剑6 小时前
【C++:继承】面向对象编程精要:C++继承机制深度解析与最佳实践
开发语言·c++·人工智能·继承·c++进阶
penguin_bark6 小时前
C++ 异步编程(future、promise、packaged_task、async)
java·开发语言·c++
小龙报6 小时前
《数组和函数的实践游戏---扫雷游戏(基础版附源码)》
c语言·开发语言·windows·游戏·创业创新·学习方法·visual studio
又是忙碌的一天6 小时前
Java基础 与运算
java·开发语言
liu****6 小时前
笔试强训(八)
开发语言·算法·1024程序员节
m0_748241236 小时前
Java注解与反射实现日志与校验
java·开发语言·python
nianniannnn7 小时前
Qt布局管理停靠窗口QDockWidget类
开发语言·数据库·c++·qt·qt5·qt6.3