🫠前言🫠
前面我们完整的学完了结构体的相关知识点,而在我们的自定义类型中还有另外两个有趣又实用的成员—— 枚举 与 联合 。通过灵活合理的使用它们就能使它们变成我们学习与工作中的好帮手,而本文就将带领大家在最短的时间内学会这两个好帮手的相关知识。
😃一:枚举😃
枚举 是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。是一个被命名的整型常数的集合。简单来说就将某种特定类型的对象一一进行列举,一一列举特定类型可能的取值。
说白了,枚举常量属于枚举类型,值是整形。
1.1:枚举类型的定义:
枚举类型的定义形式如下:
#include<stdio.h> //枚举类型1: enum Sex { MALE, FEMALE, SECRET }s1 = MALE; //声明时进行定义与初始化(全局) enum Sex s2 = FEMALE; //声明时进行定义与初始化(全局) //枚举类型2: enum Day { Mon, Tues, Wed, Thur, Fri, Sat, Sun }; int main() { enum Day s3 = Mon; //定义与初始化(局部) return 0; }
上面代码中的 enum Sex 就是我们定义出来的一个枚举类型。我们发现它和结构体的声明十分相似,但也有不同的地方
结构体中的关键字是 struct 而枚举的关键字是 enum ;
结构体的 { } 里面是结构体的成员列表,而枚举的 { } 里是枚举未来的可能取值,这些值是不能被修改的,因此我们也把这些值叫做枚举常量;
最后一点不同在于,结构体的每一个成员后边都要加 : 隔开,而枚举常量之间是用 , 加以区分。
1.2:枚举的取值:
通过打印我们发现,枚举常量的默认取值是从 0 00 开始的,每次递增 1 11 。当然我们在定义枚举类型的时候,也可以给他们赋初值:
此时这三个枚举常量的值就不再是 0 ,1,2了,而是我们初始化赋值的 1 、2、4。如果只初始化枚举常量其中的某一个,后面的枚举常量会在当前初始化值的基础上,每次自增 1.
如上,我们只初始化了枚举常量中的 FEMALE 给它赋值成 2,MALE 还是默认的从 0 开始,SECRET 则是在它前一个枚举常量 FEMALI 2 的基础上自增了 1 。
1.3:枚举的优点:
于是这里就产生了一个问题,枚举类型的成员均为常量,不可在使用中被修改,那么我们同样可使用宏 #define 去定义常量,为什么非要使用枚举类型呢?
这是因为,相比于宏,枚举类型具有很多优点:
增加代码的可读性和可维护性
和 #define 定义的标识符比较,枚举有类型检查,更加严谨
防止了命名污染(封装)
便于调试,#define在调试的时候会完成替换
使用方便,一次可以定义多个变量
1.4:枚举的大小:
已给枚举变量,只会用来存放一个枚举常量的值,所以一个枚举变量的大小应该就是一个 int 的大小,也就是4个字节。下面我们通过代码来测试一下。
1.5枚举的使用:
enum Color//颜色 { RED=1, GREEN=2, BLUE=4 }; enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。 clr = 5;//避免这样写,c++会报错
😊二:联合(共用体)😊
2.1:联合类型的定义:
联合也是一种特殊的自定义类型,这种类型定义的变量也包含有一系列的成员,但不同的是这些成员共用同一块空间(遂也被称作共用体)
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
可以看出, un 、 un.c 、 un.i 它们三个的起始地址都一样,这也说明,联合体的成员确实会共用同一块内存空间。
2.3:联合大小的计算:
联合的大小至少是最大成员的大小
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
我们来看看以下代码的结果:
#include<stdio.h> //联合体1: union TEST1 { char c[5]; int i; }; //联合体2: union TEST2 { short c[7]; int i; }; int main() { //检查联合体的大小: printf("The size of TEST1 is %d\n", sizeof(union TEST1)); printf("The size of TEST2 is %d\n", sizeof(union TEST2)); return 0; }
在联合体 TEST1 中,占用空间最大的成员是 char 类型数组 c ,且其中含有 5 个元素,则其所占空间大小为 5 个字节,而我们都知道 VS 的对齐数默认为 8 ,则将会对齐至默认对齐数 4 的整数倍,即 8 个字节;而联合体 TEST2 中,占用空间最大的成员是 short 类型数组 c ,且其中含有 7 个元素,则其所占空间的大小为 14 个字节,那么就将会对齐至对齐数 4 的整数倍,即 16 个字节;
2.4:判断当前机器的大小端:
联合体最大的特点就是:联合体的成员是共用同一块内存空间的.
于是,我们可以想一想,既然联合体的大小会随着内部成员大小的变化而变化,那么是不是联合体类型也可以通过判断内容大小,来帮助我们判断机器的大小端存储模式呢?
我们直接开始实践:
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* 的指针,再去解引用。
😐总结:😐
枚举和联合体相关的知识现在使用的其实比较少,需要在以后的工作中才会慢慢体会到他的好处!自定义类型在我们未来的工作中将会频繁的使用到。所以各位小伙伴们对于自定义类型的使用一定要烂熟于心,下去以后一定要多加练习,牢固掌握
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!