首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >自定义类型 - 联合体与枚举(百度笔试题算法优化)

自定义类型 - 联合体与枚举(百度笔试题算法优化)

作者头像
云泽808
发布2025-12-30 17:25:28
发布2025-12-30 17:25:28
1220
举报

一、联合体

1.1 联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。

在联合体里编译器只为最大的成员分配足够的内存空间,所以联合体的特点是所有成员共用同一块内存空间,所以联合体也叫:共用体

给联合体其中一个成员赋值,其他成员的值也跟着变化。

所以联合体一般所占用的空间也更小

1.2 联合体的特点

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

这里具体再看一下联合体及成员的内存是怎么分配的

在这里插入图片描述
在这里插入图片描述

这里输出的三个地址一模一样,其un的内存布局如下图:

在这里插入图片描述
在这里插入图片描述

还可用下面的例子验证其存储原理

在这里插入图片描述
在这里插入图片描述

这里确实开辟了四个字节的空间

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里改了c的值,连同i一起改了,验证了联合的成员是共用同一块内存空间的,这就是联合体与结构体的本质区别,结构体是给每个成员分配一块空间的。

1.3 相同成员的结构体和联合体对比

代码语言:javascript
复制
struct S
{
	char c;
	int i;
};
struct S s = { 0 };
代码语言:javascript
复制
union Un
{
	char c;
	int i;
};
union Un un = { 0 };

联合体和结构体内存布局情况:

在这里插入图片描述
在这里插入图片描述

所以联合体和结构体的使用情景是不同的

1.4 联合体大小的计算

  • 联合的大小至少是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
在这里插入图片描述
在这里插入图片描述

按照第一点,Un1的大小应该是5个字节,Un2的大小应该是14个字节,出现这样的结果就涉及到第二点了

首先,数组在计算对齐数时,是按照元素来算的,数据类型为char,自身的大小为1,vs上默认对齐数为8,最终对齐数取较小值为1,这又涉及我上一篇关于对齐数的解析了深入解析自定义类型:结构体与位段 所以Un1的最大成员大小为5,不是最大对齐数4的整数倍,所以要对齐最大对齐数的整数倍,所以联合体大小为4的倍数,8,相当于浪费了3个空间用于对齐。

对于Un2也一样分析,数组的数据类型为short,自身大小为2,vs默认对齐数为8,最终对齐数取较小值2,i的数据类型为int,自身大小为4,小于vs默认对齐数8,所以i的最终对齐数为4 Un2的最大成员大小为14不是最大对齐数4的对数,所以联合体大小为16,浪费2个空间用于对齐。

使用联合体是可以节省空间的,如下例: 现在商场要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。 每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息

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

总结下来就是下图:

在这里插入图片描述
在这里插入图片描述

单用结构体的话,写出来的程序就如下图

在这里插入图片描述
在这里插入图片描述

上述结构体构想的时候很简单,用起来也很方便,但是结构的设计包含了所有礼品的各种属性,图中红框成员在对应商品上就没有用上,这样就使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息是常用的。 比如: 商品是图书,就不需要设计,可选颜色,可选尺寸了。

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

代码语言:javascript
复制
struct gift_list
{
	int stock_number;//库存量
	double price;//定价
	int item_type;//商品类型

	union {//结构体可以匿名,联合体也可以
		struct
		//这里3个匿名结构体创建的成员不一样,所以是三个单独的匿名结构体类型
		//所以符合匿名结构体只能使用一次的规则
		//这三个结构体变量不会同时存在,礼品之中三选一
		//所以这三者可以共用一片空间了
		{
			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;
};

union item:根据item_type的值,存储对应类型的礼品详细信息 共用体的特点是所有成员共享同一块内存空间,因此item的大小取决于其最大成员。这里最大的成员是shirt结构体(30+4+4=38 字节),所以item占用 38 字节。 item(38 字节,但需对齐到 4 的倍数,故为 40 字节)

1.5 联合练习

深入解析数据在内存中的存储 - 大小端字节序和字节序判断(百度笔试题) 在上面这篇文章是这样写的

在这里插入图片描述
在这里插入图片描述

这里使用联合体的知识进行改进

在这里插入图片描述
在这里插入图片描述

二、枚举类型

2.1 枚举类型的声明

顾名思义枚举的意思就是一一列举,把可能的取值一一列举出来,例如:

  1. 一周的星期一到星期日
  2. 性别:男,女,保密
  3. 12个月
  4. 三原色

用代码表示如下:

代码语言:javascript
复制
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

enum Sex//性别
{
	MALE,
	FEMALE,
	SECRET
};

enum Color//颜色
{
	RED,
	GREEN,
	BLUE
};
  • 代码中定义的enum Day,enum Sex,enum Color都是枚举类型
  • {}中内容是枚举类型的可能取值,也叫枚举常量(即不能更改的)
  • 这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初始值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 枚举类型的优点

之前已经知道了#define定义常量,这里为什么还要会枚举呢? 枚举的优点:

  1. 增加代码的可读性和可维护性 不使用枚举是这样写计算器的
代码语言:javascript
复制
//模拟实现简单计算器
#include<stdio.h>
void menu()
{
	printf("*************************\n");
	printf("***** 1.add  2. sub *****\n");
	printf("***** 3.mul  4. div *****\n");
	printf("***** 0.exit        *****\n");
	printf("*************************\n");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 0:
			break;
		default:
			break;
		}
	} while (input);
	return 0;
}

这个不是很直观,但可以看出还是有一些可读性改进的。

代码语言:javascript
复制
#include<stdio.h>
enum Option
{
	EXIT,
	ADD,
	SUB,
	MUL,
	DIV
};

//模拟实现简单计算器
void menu()
{
	printf("*************************\n");
	printf("***** 1.add  2. sub *****\n");
	printf("***** 3.mul  4. div *****\n");
	printf("***** 0.exit        *****\n");
	printf("*************************\n");
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			break;
		case SUB:
			break;
		case MUL:
			break;
		case DIV:
			break;
		case EXIT:
			break;
		default:
			break;
		}
	} while (input);
	return 0;
}
  1. 和#define定义的标识符比较枚举有类型检查,更加严谨 define定义的标识符是没有类型的
在这里插入图片描述
在这里插入图片描述

这里8是int类型,s是Sex类型,把s = FEMALE改为s = 8。在C语言下可以运行,在C++下就不能运行了

所以不同语言对语法检测的严格程度是不同的,C++对语法的检测非常严格。

  1. 便于调试,预处理阶段会删除#define定义的符号

#define定义的MALE在编译时就将MALE全部替换为5,调试时的代码MALE与看到的代码5不是一回事。

  1. 使用方便,一次可以定义多个常量
  2. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。

总结

以上就是联合体与枚举部分的全部内容了,说实话我感觉枚举的用处不大,但老师说以后工作会感受到它的具体用处,还有明天考科三,希望过。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-07-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、联合体
    • 1.1 联合体类型的声明
    • 1.2 联合体的特点
    • 1.3 相同成员的结构体和联合体对比
    • 1.4 联合体大小的计算
    • 1.5 联合练习
  • 二、枚举类型
    • 2.1 枚举类型的声明
    • 2.2 枚举类型的优点
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档