1、什么是内存对齐 还是用一个例子带出这个问题,看下面的小程 序,理论上,32位系统下,int占4byte, char占一个byte,那么将它们放到一个结构 体中应该占4+1=5byte;但是实际上,通过运 行程序得到的结果是8 byte,这就是内存对齐 所导致的。

//32位系统

include

struct{
int x;
char y;
}s;

int main()
{
printf("%d\n",sizeof(s); // 输出8
return 0;
}

现代计算机中内存空间都是按照 byte 划分 的,从理论上讲似乎对任何类型的变量的访问 可以从任何地址开始,但是实际的计算机系统 对基本类型数据在内存中存放的位置有限制, 它们会要求这些数据的首地址的值是某个数k (通常它为4或8)的倍数,这就是所谓的内存 对齐。 2、为什么要进行内存对齐 尽管内存是以字节为单位,但是大部分处理器 并不是按字节块来存取内存的.它一般会以双字 节,四字节,8字节,16字节甚至32字节为单位来 存取内存,我们将上述这些存取单位称为内存 存取粒度. 现在考虑4字节存取粒度的处理器取int类型变 量(32位系统),该处理器只能从地址为4的 倍数的内存开始读取数据。 假如没有内存对齐机制~,数据可以任意存放 现在一个int变量存放在从地址1开始的联系四 个字节地址中,该处理器去取数据时,要先从 0地址开始读取第一个4字节块,剔除不想要的 字节(0地址),然后从地址4*开始读取下- 4字节块.同样剔除不要的数据(5.6.7地 1313 1796

现在有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了,而且不需要做额外的操作,提高了效率。

3、内存对齐规则 每个特定平台上的编译器都有自己的默认“对齐 系数*”(也叫对齐模数”)。gcc中默认 pragma pack(n),n = 1,2,4,8,16来改变这一 系数。 有效对其值:是给定值#pragma pack(n)和结 构体中最长数据类型长度中较小的那个。有效 对齐值也叫对齐单位。 了解了上面的概念后,我们现在可以来看看内 存对齐需要遵循的规则: (1)结构体第一个成员的偏移量(offset)为 0,以后每个成员相对于结构体首地址的 offset 都是该成员大小与有效对齐值中较小那 个的整数倍,如有需要编译器会在成员之间加 上填充字节。 (3)结构体的总大小为有效对齐值的整数倍 如有需要编译器会在最末一个成员之后加上填 充字节。 下面给出几个例子以便于理解:

//32位系统

include

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

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

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

int main()
{
printf("%d\n",sizeof(x1)); // 输出8
printf("%d\n",sizeof(x2)); // 输出12
printf("%d\n",sizeof(x3)); // 输出8
return 0;
}

测试都是在Linux环境下进行的,linux. 默认#pragma pack(4),且结构体中最长的数 据类型为4个字节,所以有效对齐单位为4字 节,下面根据上面所说的规则以s2来分析其内 存布局: 首先使用规则1,对成员变量进行对齐: sizeof(c1)= 1
【瓜分奖池】C/C++内存对齐详解 第5张插图
【瓜分奖池】C/C++内存对齐详解 第6张插图
【瓜分奖池】C/C++内存对齐详解 第7张插图
【瓜分奖池】C/C++内存对齐详解 第8张插图
【瓜分奖池】C/C++内存对齐详解 第9张插图