结构体内存对齐和结构体实现位段
结构体内存对齐
1.结构体在内存中的存储方式和对齐规则
我们先来看一段代码
struct S
{
int a;
char b;
char c;
};
int main()
{
printf("%d", sizeof(struct S));
return 0;
}
我们利用sizeof去计算了一下struct S这个结构体的大小发现是8个字节,但是我们结构体中只存了int,char,char六个字节就足以存放这三个类型的元素为什么会申请到八个字节呢?
我们在这里就得提到一个名词叫做结构体内存对齐,什么叫做结构体内存对齐呢?
在此之前我们又得引入一个偏移量的概念偏移量顾名思义就是:偏移了多大的字节我们可以用offsetof这个“宏"不清楚的可以去这里看offsetof的详细使用方法
我们可以发现他的偏移量分别为0,4,5通过画图
可以看见大致在内存中是以这种方式存储的a,b,c三个变量但为什么最终还是浪费了两个字节的内容呢?
我们来了解结构体的对齐规则:
1.结构体中的首个成员变量必须放在偏移量为0的地方
2.从第二个成员变量开始,每个成员必须放在其对齐数的整数倍数上
对齐数的计算方法:结构体中成员变量的自身大小和编译器的默认对齐数大小选取其中的较小值(vs的默认对齐数是8但是也有编译器无默认对齐数那就取其成员变量自身的大小作为对齐数)
3.结构体的总大小必须是其成员变量中最大对齐数的整数倍
4.当存在结构体嵌套的时候,比如说A结构体中包含了结构体B,那么B的对齐数是B中所有成员变量的最大对齐数用作B的对齐数,其A的结构体大小还是按照第三条计算
以上就是计算结构体大小的四条规则
我们再来看刚刚的代码是如何对齐的
当然我们可以去修改默认对齐数利用#pragma pack(x)这个x就是你想要设置的默认对齐数,当我们修改至合理的默认的对齐数的时候我们可以节省我们的空间
2.为什么要有结构体内存对齐
我们现在用的设备多是32位或64位机器,我们以32位的机器为例,CPU
一次只能访问32个bit位的空间即四个字节的空间,如果我们是连续存放的时候如:
我们会发现这里的CPU使用了两次
但是当我们对齐的时候
这里的CPU只使用了一次,所以我们采用对齐的方式去存储就是通过牺牲空间来换取时间上的便利
用结构体实现位段
1.什么是位段
位段位段,这里的位就是指二进制位所以想用位段的前提是这个变量必须属于整形家族即(char,short,int,long…),它是通过结构体的方式去实现的其写法如图:
写法就是成员变量+:数字因为我们有时候不需要那么大的空间就可以存放我们想要存放的数据所以产生了位段这个概念,我们发现这里就只使用了两个字节而并非开辟了三个字节大小的空间,那它是怎么实现的呢?
这就是位段存放的实现
2.位段的利弊
利:位段可以帮我们节省空间,因为结构体能做到的使用位段也大致都可以只要你知道你需要的内存大小
弊端:不可以跨平台使用,因为C语言对待位段的定义不够明确,所以每种编译器在处理位段和结构体大小的时候会有所差异,所以当我们要写跨平台项目的时候不推荐使用位段
且int 位段被当成有符号还是无符号的数也不确定
位段中最大位也不确定就是到底是32位机器还是64位机器,不同的机器也会有差别,所以跨平台问题严重,希望各位好好辨别,谨慎使用位段!