目录

  • 一:枚举
    • 1.1:枚举类型的定义:
    • 1.1:枚举的优点:
    • 1.2:枚举的使用:
  • 二:联合(共用体)
    • 2.1:联合类型的定义:
    • 2.2:联合类型的特点:
    • 2.3:联合大小的计算:
    • 2.4:判断当前机器的大小端:

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

一:枚举

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

1.1:枚举类型的定义:

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

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

枚举常量的取值:


通过打印我们发现,枚举常量的默认取值是从 000 开始的,每次递增 111 。当然我们在定义枚举类型的时候,也可以给他们赋初值

此时这三个枚举常量的值就不再是 000 111 222 了,而是我们初始化赋值的 111 222 444 。如果只初始化枚举常量其中的某一个,后面的枚举常量会在当前初始化值的基础上,每次自增 111


如上,我们只初始化了枚举常量中的 FEMALE 给它赋值成 222MALE 还是默认的从 000 开始,SECRET 则是在它前一个枚举常量 FEMALI 222 的基础上自增了 111

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

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;}//结果:400EFFA2C00EFFA2C00EFFA2C

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

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

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