【C语言进阶】枚举与联合体

举报
春人. 发表于 2023/11/27 00:41:20 2023/11/27
【摘要】 前言: 之前我们已经学过了自定义类型中的结构体,忘了的伙计可以再去看看。今天我们继续学习自定义类型中的另外两个成员—— 枚举和联合一:枚举 枚举顾名思义就是 一 一 列举。把可能的取值 一 一 列举出来,比如我们现实生活中的:一周的星期一到星期日是有限的7天,可以 一 一列举;性别有:男、女、保密,也可以 一 一 列举;月份有12个月也可以 一 一 列举。向这些可以 一 一 列举的数据,我们...

前言:
 之前我们已经学过了自定义类型中的结构体,忘了的伙计可以再去看看。今天我们继续学习自定义类型中的另外两个成员—— 枚举联合


一:枚举

 枚举顾名思义就是 一 一 列举。把可能的取值 一 一 列举出来,比如我们现实生活中的:一周的星期一到星期日是有限的7天,可以 一 一列举;性别有:男、女、保密,也可以 一 一 列举;月份有12个月也可以 一 一 列举。向这些可以 一 一 列举的数据,我们就可以把他们定义成枚举类型

1.1:枚举类型的定义:

enum Sex//括号里面添加的是枚举未来的可能取值,这些取值是不能被修改的,因此我们把这些值叫做枚举常量
{
	MALE,
	FEMALE,
	SECRET
};
//这就是声明了一个枚举类型

int main()
{
	enum Sex s;//定义一个枚举变量
	return 0;
}

 上面代码中的 enum Sex 就是我们定义出来的一个枚举类型。我们发现它和结构体的声明十分相似,但也有不同的地方,比如:结构体中的关键字是 struct 而枚举的关键字是 enum ;结构体的 { } 里面是结构体的成员列表,而枚举的 { } 里是枚举未来的可能取值,这些值是不能被修改的,因此我们也把这些值叫做枚举常量;最后一点不同在于,结构体的每一个成员后边都要加 : 隔开,而枚举常量之间是用 , 加以区分。

枚举常量的取值:

在这里插入图片描述
 通过打印我们发现,枚举常量的默认取值是从 0 开始的,每次递增 1 。当然我们在定义枚举类型的时候,也可以给他们赋初值
在这里插入图片描述
 此时这三个枚举常量的值就不再是 0 1 2 了,而是我们初始化赋值的 1 2 4 。如果只初始化枚举常量其中的某一个,后面的枚举常量会在当前初始化值的基础上,每次自增 1

在这里插入图片描述
 如上,我们只初始化了枚举常量中的 FEMALE 给它赋值成 2 MALE 还是默认的从 0 开始,SECRET 则是在它前一个枚举常量 FEMALI 2 的基础上自增了 1 

注意:
 枚举类型的变量在赋值的时候,最好用枚举常量来赋值

enum Sex//括号里面添加的是枚举未来的可能取值,这些取值是不能被修改的,因此我们把这些值叫做枚举常量
{
	MALE ,
	FEMALE = 2,
	SECRET 
};
//这就是声明了一个枚举类型

int main()
{
	enum Sex s = FEMALE;//最好是这样写
	enum Sex s = 2;//避免这样写 在C++中就会报错
	return 0;
}

1.1:枚举的优点:

  • 增加代码的可读性和可维护性
  •  #define 定义的标识符比较,枚举有类型检查,更加严谨
  • 防止了命名污染(封装)
  • 便于调试,#define在调试的时候会完成替换
  • 使用方便,一次可以定义多个变量

1.2:枚举的使用:

enum Color//颜色
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
clr = 5;//避免这样写

一个枚举类型变量的大小是?
 已给枚举变量,只会用来存放一个枚举常量的值,所以一个枚举变量的大小应该就是一个 int 的大小,也就是4个字节。下面我们通过代码来测试一下。
在这里插入图片描述
 可以看出一个枚举类型的大小确实就是4个字节。

二:联合(共用体)

2.1:联合类型的定义:

 联合也是一种特殊的自定义类型,它的关键字是 union 这种类型定义的变量也包含一系列的成员,特征是这些成员公用一块空间(所以联合也叫共用体

union UN
{
	char c;
	int i;
};
//定义了一个共用体类型

int main()
{
	union UN un;//定义了一个共用体变量
	return 0;
}

2.2:联合类型的特点:

 联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员),受限于联合体的特点,我们不会同时使用联合里面的成员,只会用一种的一个。

union UN
{
	char c;
	int i;
};
//定义了一个共用体类型

int main()
{
	union UN un;//定义了一个共用体变量
	printf("%d\n", sizeof(un));
	printf("%p\n", &un);
	printf("%p\n", &un.c);
	printf("%p\n", &un.i);
	return 0;
}
//结果:
4
00EFFA2C
00EFFA2C
00EFFA2C

 可以看出,unun.cun.i它们三个的起始地址都一样,这也说明,联合体的成员确实会共用同一块内存空间。

2.3:联合大小的计算:

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

举个例子:
 大家猜猜下面这个联合体的大小是多少?

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

int main()
{
	printf("%d\n", sizeof(union Un1));
	return 0;
}

 这里我们可能会想,c 的大小是5个字节,i 的大小是1个字节,取较大的,所以算出这个联合体的大小是5个字节。但实际打印出来的确是 8 ,说明这个来联合体的大小是 8 个字节,为什么呢?这是因为,我们在计算的时候忽略了上面联合体大小计算的第二点 —— 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。我们来分析一下这个联合体的大小,首先对数组 c 来说,它的对齐数是从数组一个成员的大小和默认对齐数中取较小的,这里 c 数组是 char 型,所以它的一个成员的大小是 1 个字节,vs中默认对齐数是 8 ,故数组 c 的对齐数应该是 1 i 的对齐数是从它自身大小和默认对齐数中取最小的,也就是 4 ,综上,联合的最大成员,也就是 c 的大小是 5 个字节,联合中的最大对齐数是 4 ,显然 5 不是 4 的倍数,因此来联合的大小就要对齐到最大对齐数的整数倍,5 接下来,只有 8 是最大对齐数 4 的倍数,因此最终这个联合体的大小是 8 个字节。

2.4:判断当前机器的大小端:

方法一:

int main()
{
	int a = 1;// 00 00 00 01
	//假设左边低地址————————>右边高地址
	//小端存储 - - 01 00 00 00
	//大端存储 - - 00 00 00 01
	//因此我们可以通过判断首地址处的一个字节里面存放的是0还是1来判断大小端
	if (*(char*)&a == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

方法二:

union Un
{
	char c;
	int i;
};

int main()
{
	union Un un;
	un.i = 1;
	if (un.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
	return 0;
}

 方法二这里就是利用了联合体的特性,先把联合体里的 int 型变量赋值成 1 ,再用联合体里的 char 型变量取访问,因为联合体的成员共用一块空间,且 char 型变量,一次只能访问一个字节,我们就可以通过看 char 类型访问到的是不是 1 来判断大小端,就不用再像方法一那样,取 int 型的地址,然后再强制转换成 char* 的指针,再去解引用。方法二就显得比较巧妙。

总结:
 今天的分享到这里就结束了,今天我们学习了枚举和联合体这两个自定义类型,知道了如何定义一个枚举变量以及它相较于 #define 的优点。在联合体这一块,我们知道了它的最大特点,即联合体的成员会共用同一块空间,了解了一个联合体大小的计算方法。
 如果觉得对你有帮助的话,记得点赞、评论、收藏


在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。