目录
前言
C语言除了有其内置类型,还有自定义类型。因为在实际运用中,我们可能会遇到一类数据,它的内容是由多种数据组成的,例如:一个学生的个人信息,它就包含了姓名、年龄、学号等等。这些数据并不是统一的类型,因此不能用C语言本身的数组去定义,那如果我们需要将其放在一个变量中时,我们就可以运用到结构体了。结构体的出现就是用来处理这样的内容数据不统一的变量,这给了编程者很大的操作空间,使得编程更加灵活自由。
接上篇本篇继续往下深入。
2、位段
2.1 什么是位段
位段是由结构体实现的,位段的声明和结构体是类似的,有两个不同:
1、位段的成员必须是整型家族的变量:int、unsigned int、signed int、char等等
2、位段的成员名后边有关冒号和一个数字。
比如:
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
这就是一个位段类型。如果把“:”它后面的数字去掉,那么其就是一个结构体。
冒号加后面的数字是什么意思?
冒号加数字表示给这个变量分配的空间比特位大小。那这样有什么作用呢?
举个例子,如果我们有一个变量flag,它的作用是表示真假,因此flag的取值只有0和1两种情况,所以对于flag变量来说,它不需要4个字节的空间,所以我们可以用位段将其设置为2bit。
位段的声明其实就是用来节省空间的。位段只能在结构体里面用。
下面我们分析一下,上面那个例子的空间大小,单位字节。
int main()
{
printf("%d", sizeof(struct A));
return 0;
}
答案是8。是如何计算的,下面来分析:
首先,我们位段A里面的内容是int类型,因此,在开辟空间时,按照每次4个字节的大小来开辟。先开辟4个字节(32个bit),发现,存放 _a ; _b ; _c 需要17个bit,那么还剩下15个bit位,不够放 _d,因此计算机会再开辟4个字节(32个bit)的空间,此时该位段大小来到了8字节。因此该位段式结构体大小为8个字节。
注意,冒号后面的数字是不能超过其类型的大小。比如,对于int类型,冒号后面的数字不能大于32。
2.2 位段的内存分配
举个例子:
struct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
int main()
{
struct S s = { 0 };
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
return 0;
}
我们通过画图来了解一下,再vs2019中,位段是如何分配内存的。
最终的存放结果为:
程序运行,看看内存是否是如此存储:
从右边监视图可以看出,内存中存储的的确是62 03 04,符合我们的分析。
2.3 位段的跨平台问题
对于我们上面的分析,都是基于vs2019这个平台来说的,如果换一个平台,结果可能就不一样,原因是,对于不同平台:
1、int位段被当成有符号数还是无符号数是不确定的。
2、位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出现问题)
3、位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4、当一个结构包括两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
总结:
跟结构体相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。
2.4 位段的应用
这是位段的常见运用,当我们在网上传输信息时,我们会将其用位段进行封装,像上图的一个包装,它包含了:4位版本号;4位首部长度;8位服务器类型;16位总长度等等,每一个数据都限定了长度,如果不这么做,那么每一个数据都要申请一个int类型的大小或是double类型的大小,这样的一整个信息会占用很大的空间,在互联网上,信息所占空间越小,传输会越顺畅,因此我们用位段去适当减小信息的大小,达到信息传输更迅速的目的。
总结
关于结构体中的位段这部分内容,就讲到这里了,希望对大家有所帮助。