内存对齐浅析

引入

在了解内存对齐之前,我们先来做个简短的测试。
看看下面的代码输出的结果。

#include<iostream>
using std::cout;

struct test{
	int x;
	char y;
};

int main(){
	
	test t;
	cout<<sizeof(t); //输出结果是多少?
	
	return 0;
}

如果你的答案是8,那么恭喜你答对了,不过相信很多人并不理解为什么是8,而不是5。按照正常思路,32位系统下,int4个字节,char1个字节,4+1=5,所以t5个字节,sizeof应该返回5,那为什么是8呢?
这就涉及到了文章的主题,内存对齐

内存对齐的原因

原因主要分两部分,平台原因和性能原因。

平台原因

因为现代计算机中内存的最小单位是byte,所以从理论上讲似乎对任何类型的变量的访问可以从任何地址开始。
但是实际上有些硬件平台对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地址的值是某个数k(通常它为4或8)的倍数

性能原因

假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的联系四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器,这需要做很多工作。

内存对齐规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma
pack(n),n=1,2,4,8,16
来改变这一系数,其中的n就是你要指定的“对齐系数”。

有效对其值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位

对齐规则

1、数据成员对齐规则

结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset0的地方,以后每个数据成员的对齐按照#pragma
pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、结构(或联合)的整体对齐规则

在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma
pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

3、结合1、2

当#pragma pack的n等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

案例分析

#include<iostream>
using std::cout;
using std::endl;
struct
{
   char c1;
    int i;
    char c2;
}x1;


struct {
    char c1;
    char c2;
    int i;
}x2;

int main()
{
    cout << sizeof(x1) << endl;  // 输出12
    cout << sizeof(x2) << endl;  // 输出8
    return 0;
}

以上测试都是在Win32环境下进行的,默认#pragma pack(4),因此对齐单位4

x1对象分析,首先使用对齐规则1,对x1数据成员进行内存对齐

sizeof(c1) = 1 < 4(对齐单位) 所以按照1字节对齐,占内存的第0单元。
sizeof(i) = 4 < = 4(对齐单位) 相对于结构体首地址的偏移要为4的倍数,占内存的4,5,6,7单元。
sizeof(c2) = 1 < 4(对齐单位) 相对于结构体首地址的偏移要为4的倍数,占内存的第8单元。

接着,使用对齐规则2,对结构体整体进行内存对齐

x1中变量i占用内存最大占4字节,而有效对齐单位也为4字节,两者较小值就是4字节。因此整体也是按照4字节对齐。由对齐规则1得到x19个字节,此处再按照对齐规则2进行整体的4字节对齐,所以整个结构体占用12个字节。x1内存布局
x2对象的分析也是类似。
先套用对齐规则1c1c2都是按照1个字节对齐,分别占用内存的第01单元,i相对于结构体首地址的偏移要为4的倍数,占内存的4,5,6,7单元。
再套用对齐规则2,因此整体也是按照4字节对齐。由对齐规则1得到x28个字节,此处再按照对齐规则2进行整体的4字节对齐,所以整个结构体占用8个字节。

参考资料:
内存对齐_百度百科
C/C++内存对齐详解 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鞠杉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值