内存对齐原则


参考: 内存对齐原则

#pragma pack(n)

1内存对齐原则

先看一个例子:

#include<iostream>
using namespace std;

struct S1
{
	char c1;
	char c2;
	int i1;
};
struct S2
{
	char c1;
	int i1;
	char c2;
};
int main()
{
	cout <<"sizeof(S1)"<< sizeof(S1)<<endl;
	cout << "sizeof(S2)"<<sizeof(S2)<<endl;
	return 0;
}

运行结果如下:
在这里插入图片描述
之所以会出现上面的结果,是因为结构体存在内存对齐原则,具体原则如下:

  1. 每个结构体变量的地址空间为[0,sizeof(S)],而结构体中的第一个成员变量偏移量为0,即从头开始。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍地址处,对齐数 = min{编译器默认对齐数,该成员变量大小},在windows中,编译器默认对齐数为8;
  3. 结构体大小为最大对齐数的整数倍
  4. 如果嵌套结构体,则嵌套结构体当成一个普通成员变量处理。
    因此,上面程序中结构体S1的内存分布图如下:在这里插入图片描述
    S2的内存分布图为:
    在这里插入图片描述

2 更多例子

嵌套结构体

#include<iostream>
using namespace std;
struct S1
{
	double d1;
	double d2;
};
struct S2
{
	char c1;
	S1 s1;
	char c2;
};
int main()
{
	cout <<"sizeof(S1):"<< sizeof(S1)<<endl;
	cout << "sizeof(S2):"<<sizeof(S2)<<endl;
	return 0;
}

在这里插入图片描述

类的对齐

对于类的某个实例(对象)而言,成员函数、静态变量都不会占空间,只有成员变量占空间,而只考虑成员变量的类相当于一个结构体,其对齐原则同上:

#include<iostream>
using namespace std;

class S1
{
	char c1;
	char c2;
	int i1;
};
class S2
{
	static double static_c;//静态成员
	char c1;
	char c2;
	int i1;
	int fun1()//成员函数
	{
		c1 = 'c';
		return 0;
	}
};
int main()
{
	S1 s1;
	S2 s2;
	cout <<"sizeof(s1):"<< sizeof(s1)<<endl;
	cout << "sizeof(s2):"<<sizeof(s2)<<endl;
	return 0;
}

在这里插入图片描述

为什么要对齐

CPU把内存当成一块一块的,块的大小可以是2字节、4字节、8字节等,因此CPU读取内存时是一块一块读取的,块的大小成为内存读取粒度,可以用预编译指令#pragma pack(n)来设置。

如果内存不对其将会影响CPU的读取效率,例如:
假设CPU要读取一个4字节大小的数据到寄存器中(假设内存读取粒度是4),分两种情况讨论:
1)数据从0字节开始
2)数据从1字节开始
解析:
1)当数据从0字节开始的时候,直接将0-3四个字节完全读取到寄存器,读取一次就可以了。
2)当数据从1字节开始的时候,问题很复杂,首先先将前4个字节读到寄存器,并再次读取4-7字节的数据进寄存器,接着把0字节,5,6,7字节的数据剔除,最后合并1,2,3,4字节的数据进寄存器,也就是要读取两次才能读到该数据。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值