本节重点内容:
- 什么是位段
- 位段的内存分配
- 位段的跨平台问题
- 位段的应用
1.什么是位段
位段的声明和结构是类似的,有两个不同:
1.位段的成员大多是 int、unsigned int 或signed int 也可以是char类型的(属于整形家族)。
2.位段的成员名后边有一个冒号和一个数字。
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
位段的“位”其实指的是二进制位 。
位段到底是如何分配空间的呢?位段到底占多大空间呢?(1个字节是8个bit位)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};//47bit
int main()
{
struct A sa = { 0 };
printf("%d\n", sizeof(sa));
return 0;
}
输出结果如下:
本身没有优化之前应该是4个int型16个字节,共16*8=64bit位 ,经过优化之后只占8个字节。相较于原来的16个字节省了8个字节,如果只按位段的需求只需要47位,只浪费了(8*8-47=)17个bit位。其实已经节省了很多空间了。
2.位段的内存分配
- 位段的成员可以是 int、 unsigned int、 signed int 或者是 char (属于整形家族)类型。
- 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
- 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
需要注意的是第三点,C语言并没有规定说申请剩余的空间并不能够下一个成员进行使用,虽然分配了空间,但是该空间要不要被利用掉,这种事情是不确定的,取决于编译器。同时开辟空间后申请的比特位,到底是从高向低使用还是从低向高使用?因为存在多种不确定的因素,因此位段是不跨平台的,同时注意可移植的程序避免使用位段。
那么我们在vs的环境下进行实验位段是如何开辟空间的:
//vs环境下位段的内存分配
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
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;
}
在vs的环境下通过内存调试得到结果:
(内存中每4个二进制位为1位十六进制位)
分析:
0110=6 0010=2 0000=0 0011=3 0000=0 0100=4
首先为char类型的也就是申请空间时,应该申请1个字节,共1*8个bit位,然后分别计算出abcd的二进制表示,分配到的内存中的比特位是从右向左使用,根据申请多大位段再放入多少二进制位(二进制位长度大于位段长度的只取位段长度,二进制位长度小于位段长度的在前面进行补0填充二进制位长度),之后对于分配的内存剩余比特位不够使用时,浪费掉,再从新的空间进行分配。
注意:这里仅仅是vs的环境下位段的开辟空间,不同编译器会有不同的结果。
3.位段的跨平台问题
- int 位段被当成有符号数还是无符号数是不确定的。(不同的编译器会有所差异)
- 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。(16位机器上整形int大小为2个字节有16个bit位,如果位段申请30,可能编译不过去)
- 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
- 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。
总结:
跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。
4.位段的应用
数据传输的格式封装:
应用场景分析:例如我们在网上聊天时,A想发送一条信息“hello”给B。
为了保证信息能更够准确的传输给B而不是其他人,不仅仅是把数据传给另一方,而且也需要很好的格式的分装。而这些分装中包含了4位版本号,8位服务类型,16位总长度等等。如果不考虑大小,随意设置成int大小,char大小,会存在了浪费空间的情况。这样整个数据包的大小变小了,这样网络传输数据就变小了。
想象一下网络高速公路上全是很大的数据传输,那么传输速度肯定会受影响。如果我们将数据进行合理的分装,这样大的“汽车”就会少一些,而且能够容纳更多的”汽车“。而且告诉“网络高速公路”的状态也会更好一些,“汽车变小”意味着数据传输更快,网络传输数据的负载下降了,可以容纳更多。
因此,我们在分装的时候把数据变小就行,所以把这些结构体成员设置成位段,这样让我们的使用效率更高。
(本节完)