结构体大小计算以及对齐规则

目录

结构体内存对齐规则(重要)

结构体大小计算3步(重要)

内存对齐有什么用

构造结构体技巧

修改默认对齐数


结构体内存对齐规则(重要)

结构体里面存有变量,当然也就占用内存。这个内存不是说有什么变量有多少变量加起来就行而是有一定规则。

对齐数 = 该结构体成员变量自身的大小与编译器默认的一个对齐数的较小值。
注:VS中的默认对齐数为8,不是所有编译器都有默认对齐数,当编译器没有默认对齐数的时候,成员变量的大小就是该成员的对齐数 

内存计算对齐规则:

1.成员排序放在结构体的内存地址里。假设结构体在0位置,第一个成员变量也就从0开始。

2.每个成员开辟的空间都是对齐数的整数倍。

2怎么理解,对齐数每个变量都有一个,2就是说给变量空间时,根据对齐数的倍数来存。就比如int 的 对齐数为4,那他只能在结构体的 0 4 8 12的位置存。

3.最终结构体的大小为最大对齐数的整数倍。

4.如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。(把结构体也当做一个变量)

结构体大小计算3步(重要)

有了对齐数的概念,我们就可以做结构体的计算了。

struct S
{
	double d;
	char c;
	int i;
};

第一步找对齐数: (默认对齐数和当前变量的大小取较小值)

第二步构思位置:(根据对齐数将成员变量放入内存中)

第三步找到最大对齐数:(结构体的最终大小根据最大对齐数来定)

 如图我们可以看到目前用到的内存是0-15,其中9 - 11浪费了(变量找位置根据对齐数找);

0 - 15为16字节,然后找到我们最大的对齐数,这里是double,为8,此时为16字节为8的倍数,所以要开辟的结构体大小就是16字节。

内存对齐有什么用

平台原因:

有两种访问内存数据的方法:1.任意访问任意位置的数据2.根据特殊类型的大小按倍数寻找。

因为不是每个平台都是1的访问方法,所以为了兼容有了内存对齐。

性能原因:

对齐后提高了访问效率:

减少总线传输次数:处理器访问内存时,对齐的数据可以在较少的内存访问周期内被读取或写入,因为它们往往与处理器的数据总线宽度对齐,从而减少了总线传输次数。

空间换时间:

因为对齐内存不免会产生一些没有用到的内存,但是效率提升。

构造结构体技巧

上面说到结构体内的变量是按顺序在内存中存储的。那更换变量的位置或许能减少空间的损耗呢?这个想法是对的

struct S1
{
	char a;
	char b;
	int c;
};//结构体1
struct S2
{
	char a;
	int c;
	char b;
};//结构体2

上面两个结构体,里面的变量交换了位置,但是S1计算得只消耗了8字节 ,但是S2消耗了12字节。两个的最大对齐数都是4,但是int在中间导致b存储完是在9字节的位置。所以为了是最大对齐数的倍数又额外开了3字节到了12字节

所以结论就是:把较小对齐数的变量放到一起

修改默认对齐数

#pragma pack()

这个预处理指令中()里填的就是对齐数

#include <stdio.h>

#pragma pack(4)//设置默认对齐数为4
struct S1
{
	char a;//1/4->1
	int b;//4/4->4
	char c;//1/4->1
};//12
#pragma pack()//取消设置的默认对齐数,还原为默认

#pragma pack(1)//设置默认对齐数为1
struct S2
{
	char a;//1/1->1
	int b;//4/1->1
	char c;//1/1->1
};//6
#pragma pack()//取消设置的默认对齐数,还原为默认

int main()
{
	printf("%d\n", sizeof(struct S1));//打印结果为12
	printf("%d\n", sizeof(struct S2));//打印结果为6
	return 0;
}

代码中第一次的默认对齐数为4,第二次的为1.最终计算结果也是不一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值