内存对齐,因为它是对C/C++程序员透明的,在很多C,C++课本中也没有讲清楚,所以今天写了这篇博客,讲述为什么需要内存对齐,内存对齐怎么计算?
为什么需要内存对齐?
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的。某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
内存对齐怎么计算?
首先,需要知道内存对齐的四个准则:
1.第一个成员与结构体变量的偏移量为0
2.其他变量要对齐到对齐数(对齐数取编译器预设的一个对齐整数与该成员大小的较小值)的整数倍地址
3.结构体总大小为最大对齐数的整数倍
接下来通过几个例子来说明问题:(在4字节的32位机上)
#include <iostream> #include<stdio.h> using namespace std; struct Test { int a; char b; short c; }; int main(void) { Test test; printf("a=%p\n", &test.a); printf("b=%p\n", &test.b); printf("c=%p\n", &test.c); cout << sizeof(Test) << endl; return 0; }
输出结果:
分析过程:
1、首先确定每个成员的有效对齐值,由于这里没有指定对齐值 所以 每个成员的有效对齐值就是其自身数据类型的对齐值
a 的对齐值是 4字节(32位机上) b 的对齐值是 1字节 c 的对齐值是2字节
2、起始地址必须满足“起始地址%N = 0”
令起始地址位0x0000 按照变量的顺序存储 则 0x0000%4 = 0;满足条件 占用4个字节 0x0000-0x0003 折四个字节
变量b 的起始地址 是 0x0004%1 = 0满足条件 占用一个字节 就是0x0004
变量c 的起始地址 是 0x0005%2 !=0 所以起始地址要向后移位 知道满足条件位置 0x0006%2 = 0 满足条件 占用2字节 0x0006- 0x0007
总共占用了8字节
如果变换为这样:
#include <iostream> #include<stdio.h> using namespace std; struct Test { char b; int a; short c; }; int main(void) { Test test; printf("a=%p\n", &test.a); printf("b=%p\n", &test.b); printf("c=%p\n", &test.c); cout << sizeof(Test) << endl; return 0; }输出:
分析过程:
1、找变量的有效对齐位
还是没有指定对齐值 所以就是变量自身的对齐值 b 1字节, a 4字节,c 2字节
2、起始地址满足 对有效对齐值取余=0的条件
令其实地址为0x0000 % 1 = 0满足
变量a 的起始地址为0x0001 %4 !=0
则其实地址要向后移位 知道满足条件为止 0x0004%4 = 0 占用4个字节 0x0004-0x0007
变量c 的起始地址为 0x0008 %2
= 0 满足条件 占用两个字节 0x0008-0x0009
总共占用了10个字节的内存空间
3、圆整 结构体的有效对齐值是4 所以 总共占用的硬为(10+2)%4
= 0个字节 12个字节
再来看以下几个例子练习下:(以下例子是在VS2013上写的,默认成员内存对齐为8)
例子1:
输出:16
例子2:
输出:24
例子3:
输出:16
输出:12
附录:微软经典面试题:
#include <iostream.h> #pragma pack(8) struct example1 { short a; long b; }; struct example2 { char c; example1 struct1; short e; }; #pragma pack() int main(int argc, char* argv[]) { example2 struct2; cout << sizeof(example1) << endl; cout << sizeof(example2) << endl; cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl; return 0; }输出:
8
16
4
在网络程序中,掌握这个概念可是很重要的喔,在不同平台之间(比如在Windows 和Linux之间)传递2进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙的出了一些错的······
原文地址:http://blog.csdn.net/wws199304/article/details/45081899