(转)内存对齐

为了让CPU能够更舒服地访问到变量,struct中的各成员变量的存储地址有一套对齐的机制。这个机制概括起来有两点:第一,每个成员变量的首地址,必须是它的类型的对齐值的整数倍,如果不满足,它与前一个成员变量之间要填充(padding)一些无意义的字节来满足;第二,整个struct的大小,必须是该struct中所有成员的类型中对齐值最大者的整数倍,如果不满足,在最后一个成员后面填充。维基百科的[url=http://en.wikipedia.org/wiki/Data_structure_alignment]Data Structure Alignment[/url]页面有如下表述:
[quote]The type of each member of the structure usually has a default alignment, meaning that it will, unless otherwise requested by the programmer, be aligned on a pre-determined boundary. The following typical alignments are valid for compilers from Microsoft, Borland, and GNU when compiling for 32-bit x86:

* A char (one byte) will be 1-byte aligned.
* A short (two bytes) will be 2-byte aligned.
* An int (four bytes) will be 4-byte aligned.
* A float (four bytes) will be 4-byte aligned.
* A double (eight bytes) will be 8-byte aligned on Windows and 4-byte aligned on Linux.
* A long double (twelve bytes) will be 4-byte aligned on Linux.
* Any pointer (four bytes) will be 4-byte aligned on Linux. (e.g.: char*, int*)

The only notable difference in alignment for a 64-bit Linux system when compared to a 32 bit is:

* A double (eight bytes) will be 8-byte aligned.
* A long double (Sixteen bytes) will be 16-byte aligned.
* Any pointer (eight bytes) will be 8-byte aligned.[/quote]
验证程序如下:
#include <stdio.h>

struct s {
char a;
short b;
char c;
double d;
char e;
};

int main() {

struct s s1;

printf("%d, %d, %d, %d, %d\n",
(char*)(&s1.a) - (char*)(&s1),
(char*)(&s1.b) - (char*)(&s1),
(char*)(&s1.c) - (char*)(&s1),
(char*)(&s1.d) - (char*)(&s1),
(char*)(&s1.e) - (char*)(&s1));
printf("%d\n", sizeof(struct s));

return 0;
}

在64位linux下面运行这段代码的结果是:
[quote]0, 2, 4, 8, 16
24[/quote]
由于对齐机制的存在,实际上上面的struct在内存中是长这个样子的,共计24个字节:
struct s {
char a; //在地址为0的位置
char padding1[1]; //由于下面一个元素是short,对齐字节数为2的位数,需要补1字节
short b; //对齐到了地址为2的位置
char c; //在地址为4的位置
char padding2[3]; //由于下面一个元素是double,对齐字节数为8的倍数,需要补3字节
double d; //对齐到了地址为8的位置
char e; //在地址为16的位置
char padding3[7]; //整个struct的大小需要是对齐数最大者,也就是double的8字节的整数倍
};
如果是在32位的linux下跑上面的程序,由于double的长度还是8字节,但是对齐是4字节的了,所以前面几个成员的位置不变,而最后的padding只需要补3个字节就可以了,所以输出的结果是0, 2, 4, 8, 16及20.

对于windows,其32位和64位下double都是8字节对齐的,所以在32位和64位下跑这个程序结果都是0, 2, 4, 8, 16及24.

最后,整个struct的大小的要求是对齐值最大者的整数倍,没有什么默认的4或者8的倍数一说。如果把上面程序中的a,b,c,d,e的类型全变成char,那么最后的他们的地址会是0,1,2,3,4,整个struct的大小 sizeof(struct s)的值是5,没有任何padding发生。

以上程序实验的环境在64位centos x64上的gcc 4.1.2(32位结果加-m32参数)及Visual Studio 2008上得出。
转载自http://blog.loudly.me/2010/02/memory_alignment/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值