目录
位段的概念:
位段的内存分配:
问题1:当开辟了内存后,内存中每个比特位从右向左使用?还是从左向右使用? 这个不确定。
问题2:当前面时候,剩余的空间不足下一个成员使用的时候,剩余的空间是否使用?这个不确定。
探究VS中的位段内存分布情况:
位段的跨平台问题:
注意事项:
热知识:
位段的声明和结构是类似的,有两个不同:
比如:
位段:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
结构体:
struct A
{
int _a;
int _b;
int _c;
int _d;
};
以上代码分别是位段和结构体的对比,可以看出位段其实是基于结构体的。
位段的目的:
位段的出现,是为了节省空间的,而且位段中的位其实是比特位,或者说是二进制位。
比如:
struct A
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};
上一串代码中,int_a:2; 中的2其实是表示两个比特位,也就是两位二进制。
而整个两个比特位的本质是:当我们给一个变量赋值时,这个数值在32位比特位中其实只需要两个比特位就能表达这个值是谁,例如我们本来是要给a赋值1,但1的二进制表达是01,只需要两个比特位就能表达1,而剩下的32位就会被浪费,造成空间的损失。
以此类推,其他成员分别占据,5个比特位,10个比特位,30个比特位。
因为位段的目的是节省空间,所以整个位段的字节大小应该就是2+5+10+30=47个比特位。
按照一个字节等于八个比特位的运算原理,我们可以得到差不多6个字节。
和同样类型的成员,但并不是位段的结构体进行对比:
struct A
{
int _a;
int _b;
int _c;
int _d;
};
根据结构体的对齐规则,以上结构体需要在内存中占据16个字节,和位段相比起来,位段确实是节约了空间。
但是,位段真的如我们所算计的一样,是所有比特位相加而后在进行比特位和字节的换算吗?
答案并不是。
我们先后求以上两个代码,得到以下结果:
这里涉及了位段的内存分配问题。
分配规则:
从规则得知,位段是根据成员的变量来进行开辟空间的,而不是将所有的比特位放置一个空间内,是先开辟对应类型的空间后再放置内容。
但是开辟空间后也会产生一系列的问题,这也是位段的不确定因素的原因。
例如:
struct S
{
char _a:3;
char _b:4;
char _c:5;
char _d:4;
};
因为是char类型,占据一个字节,也就是八个比特位,所以我们率先开辟八个比特位空间。
那么问题来了,变量a是只能放置三个比特位再这一个字节中,但我们是从空间的右边往左边放,还是从字节的左边往右边放?
如果,从空间的右边往左边放,分别放了a(三个比特位)和b(四个比特位),那么剩下的那一个比特位(一个字节一共八个比特位),是否需要放置下一个变量的比特位?
若我们下一个变量c(五个比特位)在开辟一个空间进行放置,后面的变量d(四个比特位)也是如此 ,(c所占据的字节中还剩下三个比特位,不够d所有的比特位)
那么这里一共就占据了三个字节,但答案真的是如此吗?
答案真是如此,就占据了三个字节。
所以我们得到了位段再VS编译器中,就是如此分配内存的! ——注!仅仅是VS编译器。
同时我们也得到结论:位段其实也会浪费空间,但是相比于普通结构体而言,浪费的更少。
普通结构体:一共占据了四个字节。
struct S
{
char _a;
char _b;
char _c;
char _d;
};
所以最后还是节约了空间。
struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
第一步, struct S s = {0};将结构体变量初始化为0
s.a =10 将10的二进制放到char a中,但是a只能放3个比特位,而10的二进制是1010,所以只能放三个比特位,从右到左截取三个进行存放。
第二步、b=12,b可以放四个比特位,12的二进制是1100,所以四个放入刚刚a放入的空间。
第三步,该空间所剩下的比特位不够变量c(5个比特位)进行存放,所以另外开辟一共空间放入c的比特位。
而因为c是3,占据五个比特位,3的二进制是00011,所以存入五个进去。
第四步、同样d也需要开辟空间,且d需要四个比特位。d是4 二进制位是0100,存入新开辟的空间。
第五步、最后按照四个比特位(二进制位)一个十六进制位进行转化,最后再内存中的展示也是如此。
以上都是VS编译器中出现的位段现象!
总结:
位段在不同的编译器不同的平台效果不一样, 所以建议在一定要需要节约内存的时候使用位段,若使用位段,只能不同的平台写不同的代码。
struct A
{
int _a : 2;
int _b : 5;
int _c : 10;
int _d : 30;
};
int main()
{
struct A sa = {0};
scanf("%d", &sa._b);//这是错误的
//正确的⽰范
int b = 0;
scanf("%d", &b);
sa._b = b;
return 0;
}
1.字节就是Byte,也是B
2.位就是bit也是b
3.转换关系如下:
1)1KB=1024B
2) 1B= 8b