提示:小编建议读本篇博文之前先明白结构体大小的计算方法(结构体内存对齐)
(下面的代码结果都是在VS2022环境测试结果)
介绍:位段是以位为单位来定义结构体中成员变量所占的空间。采用位段结构既能够节省空间,又方便操作。
位段与结构体的区别:
- 位段的成员只能是unsigned int、signed int、int、char类型的数据
- 位段的成员名后面必须有一个冒号和一个数字
- 位段是以位为单位,结构体是以字节为单位,位段相较于结构体更加节省了空间
首先我们先简单看一下结构体与位段的区别图:
struct Stu
{
int a : 4;//这里的4,代表4个比特位,而不是字节!
int b : 5;//5个比特位
int c : 9;//9个比特位
int d : 28;//28个比特位
};
上面代码中,其中里面的a为4个比特位,b为5个比特位,c为9个比特位,d为28个比特位,而不是字节!!!(其中一个字节等于8个比特位......)
位段的介绍里面就说过,位段更加节省空间,那么按道理我们不妨大胆猜测一下!
上面的代码当中一共用了46个比特位,这样我们是不是可以认为需要一共需要6个字节就OK???
运行结果却可我们猜测的不同,其实位段的内存分配也是有规律的,接下来我们便可以研究一下位段的内存分配!!!
位段内存分配:
1.位段在空间上是按照4个字节(int)或者1个字节(char)来开辟空间的(32位系统)
2.位段是不跨平台的,注重可移植程序应该避免使用位段,因为它有许多不确定因素
解释第2条:
1.位段在不同的平台上储存方式是不确定的,比如上面代码,位段先一次性开辟了4个字节(因为里面是int类型,不是char类型),int a:4;int b:5; int c:9; 其中a、b、c一共占了18个比特位,剩余了14个比特位,而下面的int d:28; 中的是先使用这剩下14个比特位,再开辟4个字节来储存,还是直接开辟4个字节来储存,这是不确定的(不同的平台)。在储存数据方面,假如在一个字节(8个比特位)里面存放数据,是先从高位到低位存放数据,还是从低位到高位存放数据,这也是不确定的!
2.例如:C语言int类型在16位和32位单片机占的字节数是不同的,在32位系统当中为4个字节(小编用的就是32位系统),在16位系统当中是2个字节,所以上面图片当中的int d:28;中,d占了28个比特位(在32系统),如果把这个程序拿到16位系统中便会出错!因为int类型在16位系统当中一共才2个字节,也就是最大内存16个比特位,而这里有28个比特位,这是肯定会出错的!所以也凸显出一个关键,那就是赋予的内存大小不能超过规定大小!
3.int被当做无符号数还是有符号数在不同的平台是不确定的!
当我们熟悉上面的内容,我们就可以通过一些案例去计算我们(Vs2022环境下)的内存分配规律吧!
案例:
struct S
{
char a : 3;
char b : 4;
char c : 5;
char d : 4;
};
int main()
{
struct S ss = { 0 };
ss.a = 16;
ss.b = 12;
ss.c = 3;
ss.d = 8;
return 0;
}
大家都知道,在电脑当中数据是以二进制的形式储存的,在Vs环境下内存窗口是以16进制显示的,接下来我们就按照上面代码的过程一步一步的解析:
1. ss.a=16 16的二进制为10000 ss.b=12 12的二进制为1100 ss.c=3 3的二进制为0011 ss.d=8 8的二进制为1000
2.因为是char类型的数据,所以接下来系统首先会开辟一个字节!因为我们一开始初始化为0,所以描述为下图:
3.我们先假设二进制数据从低位往高位储存,第一个数据ss.a, 因为第一个数据限定了3个比特位,所以只能存放进去000,而且第一个字节存放完第一个数据后还剩下5个比特位,第二个数据是ss.b限定了4个比特位,第二个字节也可以存放下,所以存放进去1100,如图:
4.当我们存放第三个数据的时候,发现第一个字节不够了,那我们先假设不用剩下的那个比特位,再开辟一个字节!当我们存放第三个数据ss.c,ss.c限定了5个比特位,存放进去数据为00011,存放第四个数据的时候,发现第二个字节在剩下3个比特位,那么按照上面的结果我们再开辟一个字节来存放第四个数据,第四个数据限定了四个比特位,存放进去1000,如图:
所以我们假设一共用了3个字节!!!
5.当我们假设这样的储存的时候,小编就用VS2022环境下测试结果:
运行结果:
发现我们的假设与测试结果完全相同!!!
那么我们就可以把这样的方法作为VS环境下位段储存方法。这样我们就明白了在Vs编译环境下的位段的计算方法了!
拿出上面的代码,我们按照刚刚的方法分析会发现,一开始开辟4个字节(int 32位系统),整型a、b、c一共占了4个字节,而d自己占了4个字节!所以运行结果为8!!!
结构体与位段联合的大小计算:
struct Stu
{
char a : 4;
char b : 3;
int c;
char d : 6 ;
};
int main()
{
printf("%d\n", sizeof(struct Stu));
return 0;
}
分析:上面前两个都是char类型位段成员,那么开辟一个字节(这时偏移量为0)存放第一个和第二个数据(位段不用考虑对齐),第三个数据为int类型的结构体成员,那么只能从偏移量为4的字节开始储存,第四个数据是位段成员,所以不用考虑字节对齐,所以自己存放在偏移量为8的空间,所以一共为9个字节,但里面有结构体成员,所以整体按照结构体的内存对齐来计算字节总大小,最大对齐数位4,而9不是4的倍数,所以一直增加为12!!!所以总占字节数位12.
运行结果:
再强调一次!小编博客的计算过程全部为Vs编译环境!!!其他平台结果不一定准确.......