目录
1、枚举
1.0、什么是枚举
1.1、枚举类型的优点
2、联合体(共用体)
2.0、什么是联合体
2.1、联合体的特点
2.2、联合体大小的计算
2.2.0、联合体节省空间例子
2.3、联合小练习
1、枚举
1.0、什么是枚举
枚举,顾名思义,就是一一列举,比如一周星期一到星期天,月份一一列举,又比如颜色列举等等。
在C语言中,枚举的基本语法如下:
● 定义的enum 枚举名 是枚举类型。
● { }中的内容是枚举类型的可能取值,也叫枚举常量 。
注意,枚举常量是不能被修改的。但是可以在定义里赋初值。
enum 枚举名 { 枚举成员1, 枚举成员2, ... 枚举成员N
};
默认情况下,枚举成员的值从0开始递增,但我们也可以指定某个枚举成员的值,此时后续成员的值会在此基础上递增。
✅在这个例子中,Color是枚举的名称,而RED、GREEN和BLUE是枚举的成员。默认情况下,RED的值为0,GREEN的值为1,BLUE的值为2。
#include<stdio.h>
enum Color {RED , GREEN ,BLUE
};
int main()
{enum Color color1 = RED;enum Color color2 = GREEN;enum Color color3 = BLUE;printf("%d\n", RED); // 0printf("%d\n",GREEN); //1printf("%d\n", BLUE); //2return 0;
}
如果指定某个成员的值,后面成员的值依次递增:
1.1、枚举类型的优点
我们本来可以使用#define 定义常量,为什么非要使用枚举呢?
枚举的优点:
1. 增加代码的可读性和可维护性
比如,比如我要写一个计算器-完成整数的加法、减法、乘法、除法时,可以使用枚举类型来定义ADD、SUB等,而不是使用整数1、2等来表示。这样,当看到ADD时,我们可以立即知道它代表的是加法,而无需去查看整数对应的含义。
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
使用#define宏定义标识符时,预处理器只是简单地将宏名称替换为其对应的值,由于这种替换是在编译之前进行的,并且没有类型信息,因此编译器无法对使用这些宏的变量进行类型检查。而枚举则不同,枚举是一种类型,它定义了一组命名的整型常量。当尝试将一个非枚举类型的值赋给枚举类型的变量时,编译器会进行类型检查,并可能发出警告或错误。
3. 便于调试,预处理阶段会删除 #define 定义的符号。
4. 使用方便,一次可以定义多个常量。
5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。
2、联合体(共用体)
2.0、什么是联合体
● 像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以是不同的类型。
● 但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体。
● 这意味着,当你给联合体的一个成员赋值时,其他成员的值会被覆盖,因为它们共享同一块内存空间。
#include <stdio.h>
//联合类型的声明
union Un
{char c;int i;
};
int main()
{//联合变量的定义union Un un = { 0 };//计算连个变量的⼤⼩printf("%zd\n", sizeof(un));return 0;
}
运行结果:4
2.1、联合体的特点
联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
#include <stdio.h>
//联合类型的声明
union Un
{char c;int i;
};
int main()
{union Un un = { 0 };printf("%p\n", &un);printf("%p\n", &(un.i));printf("%p\n", &(un.c));return 0;
}
运行结果:输出的三个地址一模一样。可见联合的成员是共用同一块内存空间的
✅也可以通过下面这段代码来调试观察:
#include <stdio.h>
//联合类型的声明
union Un
{char c;int i;
};
int main()
{union Un un = { 0 };un.i = 0x11223344;un.c = 0x55;return 0;
}
内存观察:
i 的第4个字节的内容修改为55了。un 的内存布局图:
2.2、联合体大小的计算
● 联合的大小至少是最大成员的大小。注意(是至少,但不一定)
● 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
✅代码:
#include <stdio.h>
union Un1
{char arr[5]; // 5 1 8 1int i; // 4 4 8 4
};
union Un2
{short arr[7]; // 14 2 8 2int i; // 4 4 8 4
};
int main()
{//下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1)); // 8printf("%d\n", sizeof(union Un2)); // 16return 0;
}
如上面Un1中算出最大对齐数是4 ,但最大成员大小是5,所以要对齐到最大对齐数4 的整数倍,结果是8 。算Un2的大小也是一样的思路。
2.2.0、联合体节省空间例子
使用联合体是可以节省空间的。
比如:
我们要组织一个活动,参与者可以通过积分兑换三种不同的奖励:虚拟游戏皮肤、实体纪念品、和赛事访问权限。
每种奖励都有一些共同的属性:库存量、所需的积分、奖励类型,以及每种类型特有的其他信息。
其他信息:
虚拟游戏皮肤:皮肤名称、设计
实体纪念品:尺寸、设计、颜色
赛事访问权限:参赛人数
✅结构如下:
struct point_list
{//公共属性int stock_number;//库存量double points; //所需积分int reward_type;//奖励类型//特殊属性char title[20];//皮肤名称char design[30];//设计int sizes;//尺⼨int colors;//颜⾊int num_participant;//参赛人数};
上述的结构设计简单,用起来方便,但是结构的设计中包含了所有奖励的各种属性,这样使得结构体的大小偏大,比较浪费内存。
因为对于积分兑换单中的奖励来说,只有部分属性信息是常用的。
比如: 奖励是实体纪念品时,就不需要num_participant,因为它是赛事访问权限的特有信息。 所以我们就可以把公共属性单独写出来,剩余属于各种奖励本身的属性使用联合体起来,这样就可以介绍所需的内存空间,一定程度上节省了内存。
✅ 代码:
struct point_list
{//公共属性int stock_number;//库存量double points; //所需积分int reward_type;//奖励类型union {struct{char title[20];//皮肤名称char design[30];//设计}game_skin;struct{int sizes;//尺⼨int colors;//颜⾊char design[30];//设计}souvenir;struct{int num_participant;//参赛人数}rights;}reward;};
2.3、联合小练习
✅写一个程序,判断当前机器是大端?还是小端?这个练习之前也做过,现在我们运用联合体知识实现。
#include<stdio.h>
union Un
{char c;int i;
};int main()
{union Un un = { 0 };un.i = 1; if (un.c == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}
⛳ 点赞☀收藏 ⭐ 关注!
如有不足欢迎评论区指出!
Respect!!!