【C语言进阶】枚举和联合
目录
1.枚举
1.1 枚举的优点
2. 联合(共用体)
2.1 联合体的大小计算
1.枚举
顾名思义一一列举。例如生活中:一周的七天、性别的男女、月份的12个月等等。这些值都是可以穷举的,那么就可以使用枚举。枚举类型中包含枚举常量,每一个枚举常量其实就是一个数值;从0开始依次递增1。
如果想要从1开始递增的话,我们可以人为地在第一个Mon中赋值为1;
枚举跟结构体一样,只是类型,当我们真正创建变量的时候才会在内存中开辟空间;如下图:
1.1 枚举的优点
我们可以使用define来定义常量,那么我们为什么要使用枚举来定义常量呢?
①增加代码的可读性和可维护性。
讲到这里,我们之前写过的结构体练习:通讯录中有这么一段代码:当执行到swich语句的时候,我们如何能够确定具体的分支例如case 1是代表着什么呢?
我们可以使用枚举来代替其中的常量,这样一来代码就有很高的可读性了。
② 枚举是有类型的,在c语言中对于类型的检测不够严谨,在cpp中如果你给枚举变量赋于其他的值,那么在编译的时候就会报错:
③ 防止命名污染(封装)。
④便于调试。#define在编译之前做预处理的时候直接替换相应的值,我们可以看见在调试的时候是在预处理的后面,也就是说这里是直接看不到宏定义的,只能看到被宏定义替换的常量。
但是枚举不同 ,枚举不是单纯的替换,在调试代码的时候能够看到相应的枚举类型。
2. 联合(共用体)
联合也是自定义类型,这种类型定义的变量也包含一系列的成员,这些成员共用同一块空间。下面的例子,char类型占用一个字节,int类型占用4个字节,所以创建的变量至少得5个字节,但是输出了4个字节,这是为什么呢?
共用体的精髓就在这里 ,我们将结构体变量以及结构体变量的成员进行地址的打印,发现这三个地址是一样的。
u的地址和a的地址相同很好理解,那么c的地址和a的地址相同说明,至少在第一个字节中他们存放的数据空间是重合的。
这里可以理解为合租和独立房间的区别,如果是结构体的内存,每一个变量不仅有单独的空间,还有“公摊”面积(浪费的空间);对于联合体,多个变量共用一个空间,类似于合租。
联合体最巧妙的用法是,当联合体内的变量不是同时要用,那么联合体的优势就体现出来了,例如上图,如果用c的时候,只会占用一个字节,如果用a的时候就会用4个字节。
所以联合体至少有能力保存最大的那个成员。
在内存中我们可以清晰地看见,在第一个字节处存的是c,再后三个字节处存的是a。
先看一个我们曾经写过判断系统大小端的代码,底层逻辑是内存的存储。
int check_sys()
{int a = 1;return *(char*) & a;// 小端 0x 01 00 00 00// 大端 0x 00 00 00 01
}int main()
{if (check_sys()) {printf("小端");}else {printf("大端");}
}
我们可以用共用体来改写一下这个代码:
int check_sys_union()
{union Un{char i;int j;}u;u.j = 1;return u.i;
}int main()
{if (check_sys()) {printf("小端");}else {printf("大端");}
}
这两个代码的底层逻辑都是先让整型存储1,占用4个字节,这时候只需要取出第一个字节,判断第一个字节究竟存的是什么即可,共用体利用了先天的优势,直接可以读取第一个字节的内容,如果不用 共用体,我们得强制类型转换才能获得第一个字节。
共同体和结构体一样,如果只是在函数内部使用一次,那么就可以匿名,写法雷同于结构体;
union
{char i;int j;
}u;
2.1 联合体的大小计算
一般情况下是选择联合体内较大的那个元素类型的大小,下面这种情况需要内存对齐:
一个char数组的对齐数是char也就是1,int的对齐数是4,最大对齐数是4,所以整体需要4的倍数个字节,如果是4就存不下第一个数组,所以是8;
判断下列的共用体的大小:
①short的对齐数是2;int的对齐数是4,;
②所以整体必须是4的倍数,2 * 7 = 14个字节,足够存下i了,又要满足是4的倍数,所以是16个字节。