【结构体内功修炼】枚举和联合的奥秘(三)

在这里插入图片描述

文章目录

  • 1. 枚举
    • 枚举类型的定义
    • 枚举的优点
    • 枚举的使用
  • 2. 联合(共用体)
    • 联合类型的定义
    • 联合的特点
    • 联合的应用
    • 联合大小的计算

在这里插入图片描述

1. 枚举

枚举顾名思义就是一一列举。

把可能的取值一一列举。

比如我们现实生活中:

1、一周的星期一到星期日是有限的7天,可以一一列举。

2、性别有:男、女、保密,也可以一一列举。

3、月份有12个月,也可以一一列举

这里就可以使用枚举了。

枚举类型的定义

代码示例

enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

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

enum Color//颜色
{
	RED,
	GREEN,
	BLUE
};

以上定义的 enum Dayenum Sexenum Color 都是枚举类型。

{ }中的内容是枚举类型的可能取值,也叫 枚举常量

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

代码示例

#include 

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


int main()
{
	printf("%d\n", MALE);
	printf("%d\n", FEMALE);
	printf("%d\n", SECRET);

	return 0;
}

运行结果
【结构体内功修炼】枚举和联合的奥秘(三)_第1张图片

枚举的优点

为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?

#define MALE 4
#define FEMALE 5
#define SECRET 6

枚举的优点:

1、增加代码的可读性和可维护性;

2、和 #define 定义的标识符比较枚举有类型检查,更加严谨;

3、防止了命名污染(封装);

4、便于调试, #define 定义的常量是不能进行调试的

5、使用方便,一次可以定义多个常量

枚举的使用

代码示例

#include 

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};

int main()
{
	enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。

	clr = 5;

	return 0;
}

2. 联合(共用体)

联合类型的定义

联合也是一种特殊的自定义类型;

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

代码示例

#include 

union Un
{
	char c;
	int i;
};

int main()
{
	union Un u;

	printf("%d\n", sizeof(u));

	return 0;
}

那么 u 占多少个字节呢?我们打印看一下
【结构体内功修炼】枚举和联合的奥秘(三)_第2张图片
为什么是 4 呢?

别急,我们把 u 和它的成员地址全部打印出来看一看
【结构体内功修炼】枚举和联合的奥秘(三)_第3张图片
我的天啊,它们三个的地址为啥都是一样的呢?

uu.cu.i 它们都指向第 1 个字节首地址;

c1 个字节,i4 个字节;

也就是 ic 共用了第 1 个字节;

当我给 c 赋值的时候,我就把 i 的第一个字节给改变了;

当我给 i 赋值的时候,整个 c 也就被改了;
【结构体内功修炼】枚举和联合的奥秘(三)_第4张图片
所以 联合体 比较特殊的地方在于:对于联合体的成员在同一时间只能用 1 个;

代码示例

#include 

union Un
{
	char c;
	int i;
};

int main()
{
	union Un u = { 0 };

	u.c = 'w';

	u.i = 0x11223344;

	return 0;
}

我们在内存中看一下调试结果

首先把第 1 个字节改为 w
【结构体内功修炼】枚举和联合的奥秘(三)_第5张图片
然后又把整个 i 的内容改为 0x1223344
【结构体内功修炼】枚举和联合的奥秘(三)_第6张图片

联合的特点

1、联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小;

2、因为联合至少得有能力保存最大的那个成员;

联合的应用

比如我现在要设计一个 学校用户系统

1、学生:姓名、年龄、身份

2、老师:姓名、年龄、职称

代码示例

union type
{
	identity; //身份
	title; //职称
};

struct UserInfo
{
	char name[20];
	int age;
	union type t;
};

身份职称 都是相似的值,但它们只会用 1 个;

来看一道面试题:判断当前计算机的大小端存储

首先来看看什么是 大小端字节序

1、小端存储:假设 01 是低位字节的内容,00 是高位字节的内容,把低位字节的内容 01 放在低地址处,高位字节的内容 00 放在高地址处,这种存储方式叫 小端存储
【结构体内功修炼】枚举和联合的奥秘(三)_第7张图片
1、大端存储:假设 01 是低位字节的内容,00 是高位字节的内容,把低位字节的内容 01 放在高地址处,高位字节的内容 00 放在低地址处,这种存储方式叫 大端存储
【结构体内功修炼】枚举和联合的奥秘(三)_第8张图片
那么如何用代码来实现呢?

其实很简单,我们可以拿出第 1 个字节的内容,如果第 1 个字节的内容是 1,那么就是 小端存储;如果第 1 个字节的内容是 0,那么就是 大端存储

代码实现

#include 

int check_sys() {
	int a = 1;
	return (*(char*)&a);
}

int main()
{
	int ret = check_sys();

	if (1 == ret) {
		printf("大端\n");
	}
	else {
		printf("小端\n");
	}

	return 0;
}

运行结果
【结构体内功修炼】枚举和联合的奥秘(三)_第9张图片
我们可以看到,aint 类型,但我们在 check_sys() 实际使用的只有 1 个字节,那么对代码进行升级;

代码升级

#include 

int check_sys() {
	union
	{
		char c;
		int i;
	}u;

	u.i = 1;
	return u.c;
}

int main()
{
	int ret = check_sys();

	if (1 == ret) {
		printf("大端\n");
	}
	else {
		printf("小端\n");
	}

	return 0;
}

运行结果
【结构体内功修炼】枚举和联合的奥秘(三)_第10张图片
这就是巧妙的运用到了 联合体联合体 的成员会共用一块儿空间;

联合大小的计算

1、联合的大小至少是最大成员的大小。

2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

代码示例一

#include 

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

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

成员 c 的类型是 char,所以它的对齐数是按照 char 来算的,也就是 1,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 1

成员 i 的类型是 int,所以它的对齐数是按照 int 来算的,也就是 4,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 4

成员 c 的对齐数是 1,成员 i 的对齐数是 4,那么最大的对齐数就是 4,而联合体的总大小必须是最大对齐数的整数倍;

又因为 cchar 类型的数组,有 5 个元素,所以有 5 个字节;iint 类型,有 4 个字节;所以最大的就是 5 字节,但最大的对齐数是 4,不满足,所以就就是 8,也就是 42 倍。

运行结果
【结构体内功修炼】枚举和联合的奥秘(三)_第11张图片

代码示例二

#include 

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

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

cshort 类型,占 2 字节,有 7 个元素,所以占 14 字节;iint 类型,占 4 字节;

那么取 14 就能存放下 Un2 的所有成员了,但是 14 是不是最大对齐数的整数倍呢?

成员 c 的类型是 short,所以它的对齐数是按照 short 来算的,也就是 2,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 2

成员 i 的类型是 int,所以它的对齐数是按照 int 来算的,也就是 4,而 VS 默认的对齐数是 8,取其较小值,那么它的对齐数就是 4

成员 c 的对齐数是 2,成员 i 的对齐数是 4,那么最大的对齐数就是 4,而联合体的总大小必须是最大对齐数的整数倍,14 不是 4 的倍数,怎么办呢?

很简单,浪费掉 2 字节变成 16 就是 4 的倍数了。

运行结果
【结构体内功修炼】枚举和联合的奥秘(三)_第12张图片

你可能感兴趣的:(#,「C语言内功修炼」,c++,c语言,枚举,联合,结构体)