目录
1、位段
1、位段的声明
2、位段的内存分配特点
3、位段的跨平台问题
4、位段的应用
2、枚举
1、枚举类型的定义
2、枚举的优点
3、联合体(共用体)
1、联合类型的定义
2、联合体的特点即大小计算
1、位段
1、位段的声明
位段的位指的是二进制位。
位段的声明与结构体相似,但需要加上下划线_和冒号:
位段的成员必须是int,signed int,unsigned int,在大部分平台上,char类型也可以,即整型家族
例如这一段代码,给abcd分别分配了2 5 10 30 个比特位的空间。
给每个变量以比特位为单位的空间,以节省空间。(经计算,A的大小为8byte)
同时,对于int类型的abcd,给他们分配的空间是不能大于整型本身的32bit的。
即位段是一种更节省空间的结构体类型,但成员只能是整型家族。
2、位段的内存分配特点
1. 位段的成员可以是 int unsigned int signed int 或者是 char (属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。(每次开辟一定空间后使用,如果不够用再开辟)
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
对于上面的例子,int类型创建4个字节32位,a需要2bit,还剩30,继续分配b5bit,还剩25,继续分配c10bit,还剩15bit,空间无法容纳d所需的30bit,此时就需要重新开辟4byte空间的大小。因此,最终A的大小为8byte。
然而,在我们上述分析的过程中存在两个个问题。
1、分配完c后,第一次开辟的4byte中剩下的15bit,是否会被利用起来存放d的一部分内容,还是直接浪费掉?
2、每次开辟出来4byte空间的大小,我们的数据是从高地址开始存放,还是低地址?这其中是否还存在大小端字节序存储的问题?是否与编译器的实现有关?
下面我们来验证其在VS2022环境中的内存开辟和使用规则。
在VS中我们发现,由于每次开辟1个byte(char),或int每次开辟4byte,都是从低地址向高地址开辟(已经在内存中开辟,不是形成后往内存中放),用完后再开辟别的,因此不存在大小端字节序存储的问题。但是存在数据从这段空间的低位开始存储,还是高位开始存储的问题 。
VS2022中,是从这段空间的低位开始存储数据,并且多余的空间在开辟下一段空间前会被浪费。
同时,位段是不存在内存对齐的。因为本身就是为了节约空间的。
再拆开细节来说,内存对齐是由于平台原因和性能(即时间)原因两方面考虑的。
位段中由于都是整型家族,且位段的使用一般是连续的char或int类型,与cpu可以较好的兼容,因此在速度、性能上具有优势。(结构体是拿空间换时间,性能由于内存对齐也有优势)。
同时对于内存较小的数据可以更精确的集中处理,结构体只能让小的尽可能集中。
3、位段的跨平台问题
1. int 位段被当成有符号数还是无符号数是不确定的。
2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机
器会出问题。
3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是
舍弃剩余的位还是利用,这是不确定的。
4、位段的应用
在计算机网络中,例如AB两用户间数据的传输,还需要对其进行封装。封装的过程就会对空间进行额外的消耗。在如今大数据时代,我们传输的每个信息如果都要浪费不必要的空间,就会导致严重的空间浪费。因此,对于封装部分的额外数据(例如仅占用4bit或8bit),最好使用位段实现,使其“小巧”一些,即避免了空间的浪费,也进一步提高了性能,提高传输速度。(网络负载减少)
总的来说,位段就是结构体在节约空间方面的延伸,但是具有跨平台方面的问题,且成员只能是整型家族。
2、枚举
1、枚举类型的定义
把可能的取值一 一列举出来。几个可能的取值间用,分隔。
male female 都是常量,不过常量也需要一个初始值,可以对其初始化。后面递增1。不初始化,第一个默认为0。
对于枚举类型的变量s,可以给它赋值一个枚举类型的常量female,如果给它赋值一个3,3为整型类型,理论上是不可以的,在C++标准中是错误的,C语言不会报错。
2、枚举的优点
我们可以使用 #define 定义常量,为什么非要使用枚举?
枚举的优点:
1. 增加代码的可读性(通讯录case)和可维护性
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 防止了命名污染(封装)
4. 便于调试
5. 使用方便,一次可以定义多个常量
枚举常量是存放整型的,因此其大小为4byte
3、联合体(共用体)
1、联合类型的定义
联合也是一种特殊的自定义类型。这种类型定义的变量也包含一系列的成员。特点是这些成员公用同一块空间。
c和i两个变量一般不会同时使用。
2、联合体的特点即大小计算
1、联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。
2、当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。(与位段不同,因为位段只包含整型家族,联合体包含其他元素,不对齐可能会使性能下降)。
面试题,判断机器的大小端存储。
char*pa=(char*)&a,强制类型转换为char*判断第一个字节的内容是否为1。
封装成函数
位段、枚举、联合、结构体都是自定义类型,要区分它们的优缺点,以及适合的使用场景。
联合的成员一般不同时使用,即可以不同时存在,也可以一定程度上节省空间。