C语言--两种自定义类型:枚举、联合

前言

上文我们已经介绍过自定义类型之结构体,本文将继续介绍自定类型剩下的两种:枚举、联合。
本文涉及到的主要内容有:

● 枚举 :
a. 枚举类型的定义
b. 枚举的优点
c. 枚举的使用

● 联合 :
a. 联合类型的定义
b. 联合的特点
c. 联合大小的计算


一、枚举

枚举顾名思义就是一一列举。把可能的取值一一列举。
比如我们日常生活中出现的:

星期一到星期日;
某个高中生的考试科目;
1-12个月

这些内容都是有限且固定的,此时就可以使用枚举类型。


1.1 枚举类型的定义

枚举类型的一般语法:

enum tag//枚举标签
{
	member-list;//枚举成员变量
};

enum是枚举类型的关键字。

枚举示例:

enum Day//星期
{
	 Mon,
	 Tues,
	 Wed,
	 Thur,
	 Fri,
	 Sat,
	 Sun
};
enum Sex//性别
{
	 MALE,
	 FEMALE,
	 SECRET
}enum Color//颜色
{
	 RED,
	 GREEN,
	 BLUE
};
//枚举使用示例:
int main()
{
	enum Color c = BLUE;
	return 0;
}

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。
{}中的内容是枚举类型的可能取值,也叫枚举常量 。这里要和结构体做以区分,枚举内的枚举常量都是常量,是以后该枚举类型可能的取值,且在使用时不可以修改!而结构体内的结构体成员都是变量,是可以修改来描述复杂事物的。

注意枚举常量的分割是以“,”为结尾而非“;”,其中最后一个枚举变量结束没有符号。

这些可能取值都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值。
例如:

enum Color//颜色
{
	RED,
	GREEN,
	BLUE,
	YELLOW = 6,
	WHITE,
	BLACK
};
int main()
{
	printf("%d\n", RED);
	printf("%d\n", GREEN);
	printf("%d\n", BLUE);
	printf("%d\n", YELLOW);
	printf("%d\n", WHITE);
	printf("%d\n", BLACK);
	return 0;
}

输出结果:
在这里插入图片描述


1.2 枚举的优点

既然枚举类型都是常量,我们也可以使用#define来定义常量,为何选择枚举呢?

枚举的优点:

  1. 增加代码的可读性和可维护性;
  2. 和#define定义的标识符比较枚举有类型检查,更加严谨;
  3. 防止了命名污染(封装);
  4. 便于调试,枚举常量在预编译后依旧是枚举类型,而#define在预编译后直接被替换为所对应的常量;
  5. 使用方便,一次可以定义多个常量。

下面举个例子来说明枚举的一个实际使用场景:
还记得我们之前编写过的“实现计算器”的代码吗?
在菜单选择栏,我们使用switch语句来判断进行何种运算,原来是这样写的:

	switch (input)
	{
	case 1:
		Add();
		break;
	case 2:
		Sub();
		break;
	case 3:
		Mul();
		break;
	case 4:
		Div();
		break;
	case 0:
		break;
	}

这里case的值很难让我们和它所执行的内容对应起来,对于代码的阅读者也是不太友好。但是如果我们使用枚举类型来将这些数字定义成某些常量呢?

enum INPUT
{
	ADD = 1,
	SUB = 2,
	MUL = 3,
	DIV = 4
};
	switch (input)
	{
	case ADD:
		Add();
		break;
	case SUB:
		Sub();
		break;
		.....
	}

这样代码的可读性是不是更好了?当然,更多的优点需要慢慢感悟!

PS.枚举类型的大小是一个int的大小:4。因为一个枚举变量只能有一种可能的取值,就是某一个枚举常量。


二、联合(共用体)

2.1 联合类型的定义、特点

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

//联合类型的声明
union Un
{
 char c;
 int i;
};
//联合变量的定义
union Un un;
//计算联合变量的大小
printf("%d\n", sizeof(un));

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

但是联合体的大小是不是就是其成员变量中最大的那个变量的大小呢?答案是否定的,具体在2.3节讲述。

2.2 联合的一个应用示例

此处我们来看一个联合体的具体使用案例:

编写一个函数来判断机器的存储方式是大端还是小端

这道题我们之前已经实现过,当时是用了强制类型转换的思想来实现判断的,具体代码如下:

int sys_check()
{
	int a = 1;//1的16进制存储: 00 00 00 01
	if (*(char*)(&a) == 1)
	{
		return 1;//小端
	}
	else
	{
		return 0;//大端
	}
}

为了更清楚弄明白,这里仔细分析一下:

  1. 我们首先要弄清楚什么是大端存储,什么是小端存储。
    大端存储:数据的低位数据存储在内存的高地址处;
    小端存储:数据的低位数据存储在内存的低地址处;
    如下图,对于a = 1来说,其最低位数据是01。
    在这里插入图片描述
  2. 那么当机器中放入一个int型数据a时,我们只需要判断a所在地址的第一个字节的内容就可以判断出大小端了。以我们用到的int a = 1;为例:如果是1,就是小端存储,如果是0,就是大端存储。
  3. 那么问题来到了如何取出第一个字节的内容呢?
    在上面的代码中,我们首先将a的地址强制转化为char*类型,再解引用就能得到第一个字节的内容了。
    但是我们学习了联合体,既然联合体内的成员共用一片地址,那么如果使用一个下面这样的联合体,我们给i赋值1,那么c的内容不就是i的第一个字节的内容吗?
union un
{
 char c;
 int i;
};

利用联合体实现判断机器大小端函数的代码:

int sys_check()
{
	union un
	{
		char c;
		int i;
	}u;
	u.i = 1;//1的16进制存储: 00 00 00 01

	return u.c;//直接返回联合中c的内容,如果是小端就是1,大端就是0
}

2.3 联合大小的计算

  • 联合的大小至少是最大成员的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。(其中最大对齐数是联合体成员变量中占用内存最大的那个类型的大小。)
union Un1
{
	char c[5];//对齐数:1  占用:5
	int i;//对齐数:4   占用:4
};
union Un2
{
	short c[7];//对齐数:2   占用:14
	int i;//对齐数:4   占用:4
};

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

输出结果:
在这里插入图片描述

分析:

Un1:
char类型数组c占据5个字节,int类型的i占据4个字节,所以至少占5个字节。但是要对齐,因为char的对齐数是1,int对齐数是4,所以Un1的最大对齐数是4,因此Un1的大小是4的倍数,而5之后的下一个4的倍数就是8.
因此Un1大小为8

Un2:
short类型数组c占据14个字节,int类型i 占据4个字节,因此该联合至少占有14个字节。但是要对齐,因为short类型对齐数为2,int类型对齐数为4,所以Un2的最大对齐数是4。14之后的4的整数倍是16。
因此Un2的大小为16

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值