在上篇文章中介绍了部分结构体的知识后,我们这次来了解一下结构体中关于位段的知识,以及剩下的两种自定义类型——枚举、联合体,希望通过这篇文章能给大家带来帮助。
目录
一、位段
1.1位段是什么
1.2位段的内存分配
1.3位段的跨平台
二、枚举
2.1枚举类型的定义
三、联合体(共用体)
3.1联合体类型的定义
3.2联合的特点和大小
3.3使用联合体判断大小端
所谓位段就是以比特位为单位的成员,就是最小的单位是比特位,而不是字节。像int,char,long,short等都是以字节为单位的。
位段的声明与结构与结构体类似,但是有两个不同:
1.位段的成员必须是char、unsigned char、int、unsigned int。
2.位段的成员名后面有一个冒号和一个数字。
举个例子:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
int main()
{
struct A p1;
return 0;
}
其实,我们在这样定义时,这个冒号就表示只分配a两个比特位,我们使用位段的这种方式,可以极好地使用空间(位段没有内存对齐)。
我们可以使用sizeof来计算位段的大小,注意,位段的单位是比特位,一个整形有4个字节,一个字节等于8个比特位。等一会我们会探讨位段的大小为什么是这样的。
1.位段的空间是按照需要以4个字节(int)或1个字节(char)来开辟的。
在VS2019中,如果开辟的空间不足容纳这个成员的大小,则会重新开辟一个该成员类型的空间来容纳这个成员。
2.位段涉及很多不确定因素,所以位段是不夸平台的,不同编译器可能会产生不同的效果,注重可移植的程序应该避免使用位段。
以我们上面那个例子来说,他的大小是8,也就是2个int型数据的大小,明明是4个int型的位段,为什么只有两个int型数据的大小呢,我们来画图并分析一下:
我们按照第一条规则,首先,a为2个比特、b为6个比特,他俩加起来刚好8个比特,可以共占一个字节,而c一个就占8个比特,但是他们的总数没有超过32,所以,c可以共用这个整形的下一个字节,如图所示。而d就比较特殊了,他一个大小就占了30个比特,a、b、c这个整形中已经容纳不下这个成员了,所以编译器给他开辟了下一个整形,让他一共控制30个比特位(还有俩个比特位不属于d管控)。
接下来我们来看看我们的推理是否正确,我们创建一个我们自定义A类型的变量p,并对他进行初始化和赋值,再观察内存中数据的是如何存储的。
(注意,VS是小端存储哦!这虽与位段无关,位段的单位是比特位,而这中存储是以字节的方式存储,但是我们在内存中观察数据时要引起注意)
我们从内存中看到,p变量中数据的存放与我们上面推理的内容完全相符。
接下来我们来看看char型的位段是是怎样使用内存的。我们依然使用一个变量s,并对他进行赋值来分析是如何存放数据的。
位段,因为大小的限制,如果数据超过了我们定义的范围则会发生截断,如a所示。
注意,a+b共7个比特位,虽然有一个比特位剩余,但VS采取的方式是再开辟一个字节(因为c是char型数据)将c全部存放到该字节中,并没有让c干涉a+b的那块空间,这虽是允许的,但也是C语言标准未定义的。
我们可以得到数据7F 04 03 62(小端存储)对应的10进制数,来检测改变位段是否会达到我们想要的值,当然,这是多余的一步,因为内存中已经存放了我们想要的数据。
这里我们来看一些C语言标准中未定义的一些问题:
1.int位段被当成有符号数还是无符号数不确定。
2.位段中最大位的数目不能确定。(16位机器最大为16,32位机器最大32)
3.位段中的成员在内存中从左到右分配,还是从右到左分配标准尚未定义(VS中是从右到左分配)。
4.当一个结构体包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这也是未定义的(VS中是直接省略)。
总结:位段可以达到与结构体相同的效果,但是可以更好的节约空间,可以在一些特殊的场景下使用,但是他存在跨平台的问题。
我们使用枚举来将所有可能出现的情况一一列举出来,比如颜色、星期、月份等,我们就可以将所有可能列举出来,定义一个枚举类型的类型。接下来我们来看看如何定义。
以上定义的这些枚举类型中{}里的内容是枚举类型的可能取值,也叫枚举常量。
既然是常量,那必然是有值的,这些值默认是从0开始,一次递增1,在定义时我们也可以赋初始值。
枚举类型的使用还是比较常见的,因为他可以增强我的我们代码可读性和可维护性,所以说在以后代码量多的地方,枚举的优势还是十分明显的。
联合也是一种特殊的自定义类型
这种类型定义的变量包含一系列的成员,特征是这些成员公用一块空间(所以联合体也叫共用体)
这里sizeof计算u1的大小为4,即使有一个整形和一个字符型的数据,但是该共用体的大小依然是4,因为c和i共用一块空间。
1.联合体Un中的元素共占一块空间
2.联合体的总大小最小为最大成员的大小
3.当最大成员大小不是最大最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
这时我们来看一个案例:
联合体大小的计算其实和结构体的大小相似,只不过联合体的大小取决于最大成员的大小。
在之前我们使用使用char型指针判断当前编译器是大端还是小端,我们现在了解了联合体,便可以使用联合体来判断。
好了,本篇文章就介绍到这里了,结构体的知识也到这就结束了,希望能对大家有帮助。
下篇文章我会介绍动态内存管理相关的知识,我们下次再见~