结构体变量的地址受到内存对齐规则的影响,使得结构体成员并不是在内存中“紧挨”着的。
可以参照如下结构体:
1 #include <stdio.h> 2 struct s{ 3 char a; 4 double b; 5 int c; 6 short d; 7 double e; 8 }; 9 int main() 10 { 11 struct s s1; 12 printf("%x ",(int*)&(s1.a)); 13 printf("%x ",(int*)&(s1.b)); 14 printf("%x ",(int*)&(s1.c)); 15 printf("%x ",(int*)&(s1.d)); 16 printf("%x ",(int*)&(s1.e)); 17 printf("%d ",sizeof(s1)); 18 return 0; 19 }
运行结果如下:
最终,我用EXCEL表格的形式,做出如下的结构体成员的内存分配位置,如下图黄色为实际存在数据的内存单元,白色空格为适应内存对齐而进行的偏移量。需要注意系统默认是4字节对齐的,所以一行的最大宽度也就是四个字节。
所以结构体内存分配的规则个人总结如下:
1.首成员起始地址设为0。
2.每个成员x的起始地址必须是min(4,sizeof(x))的倍数。
关于总结的第2点可以在《深入理解Linux内核》内存管理章节中的“对齐内存中的对象”小节中找到依据:
slab分配器所管理的对象可以在内存中进行对齐,也就是说,存放它们的内存单元的起始物理地址是一个给定常量的倍数,通常是2的倍数。这个常量就叫对齐因子(alignment factor)。
由于系统默认4字节对齐,所以我认为文章所提到的对齐因子最大值也就是4了。即min(4,sizeof(x))。
这个规则我使用了多种情况验证,都是正确的。如有错误,还请各位大侠批评指正哈!
在VC上可以通过如下宏来改变内存对齐的字节范围,即改为8字节内存对齐
#pragma pack (8)
同样可以用《深入理解Linux内核》内存管理章节中的“对齐内存中的对象”小节中来解释内存对齐的意义:
通常情况下,如果内存单元的物理地址是字大小(即计算机的内部内存总线的宽度)对齐的,那么,微机对内存单元的存取会非常快。