下面是维基百科对位段的解释:
位段(或称“位域”,Bit field)为一种数据结构,可以把数据以位的形式紧凑的储存,并允许程序员对此结构的位进行操作。这种数据结构的好处:
- 可以使数据单元节省储存空间,当程序需要成千上万个数据单元时,这种方法就显得尤为重要。
- 位段可以很方便的访问一个整数值的部分内容从而可以简化程序源代码。
而位域这种数据结构的缺点在于,其内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
需要注意的是:
int main()
{
struct A a;
a._a = 2;
a._b = 3;
a._c = 5;
a._d = 10;
return 0;
}
相当于实例化后的a里面的不同大小的内存里放入了数据。
因为不同平台上的规则都是不太一样的,计算出来的结果也会有些许差异,以下使用vs2022的x64环境下运行的
例如:
#include
struct A
{
int _a : 2;//二进制位
int _b : 5;
int _c : 10;
int _d : 30;
};
int main()
{
printf("%d", sizeof(struct A));
return 0;
}
上面代码的输出结果是8。
#include
struct B
{
int _a : 30;//二进制位
int _b : 4;
int _d : 32;
};
int main()
{
printf("%d", sizeof(struct B));
return 0;
}
大家有没有发现,我们在声明位段的时候,如果定义的是int,那么冒号后面跟上的数字不能超过32,如果定义的是char,那么冒号后面跟上的数字不能超过8。如果超过以后,就会报出以下错误:
其实根据内存对齐原则,如果超出以后,处理器就需要访问两次才能完整的得到数据。所以在定义的时候,应该避免超出应有的内存大小。
接下来我们分析:
用例代码:
#include
struct A
{
char _a : 3;
char _b : 4;
char _c : 5;
char _d : 4;
};
int main()
{
struct A a = {0};
a._a = 10;
a._b = 12;
a._c = 3;
a._d = 4;
return 0;
}
我们假设:位段分配的内存中的比特位是从右向左使用的,分配剩余的比特位不够使用时,浪费掉剩余内存。
则:
a._b = 12;
,12的二进制为1100,刚好可以放入,如下图:a._c = 3;
,3的二进制为11,由于_c有5bit,高位添0,放入00011,如下图:a._d = 4;
,4的二进制为100,放入0100,如下图:以上也证明了, 在VS2022上,位段分配的内存中的比特位是从右向左使用的,分配剩余的比特位不够使用时,浪费掉剩余内存,重新开辟新的空间。
当然,不同平台得到的结果也可能会不同,这正是位段的缺点,可移植性差,接下来我们看看位段的跨平台问题。
总结:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
位段由于跨平台的问题,真正的用途的其中一个是计网的IP数据报:
创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看