内存对齐
转自http://blog.csdn.net/yy13210520/article/details/6841052
内存对齐原则:
一、结构体变量的首地址能够被其最宽基本类型成员大小与对齐基数中的较小者所整除;
二、结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
三、结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
关于结构体分配内存和字节对齐原则
今天看到一个关于sizeof的使用问题,并且提到了计算机组成原理中的字节对齐,写了如下测试程序,发现了一些问题:
#include <iostream>
#include <malloc.h>
#include <stdlib.h>
using namespace std;
struct S0 {};
struct S1
{
char a;
int b;
};
struct S2
{
int x;
char y;
};
struct S3
{
char c1;
S1 s;
char c2;
};
int main ()
{
cout << "Testing S0 ...\n";
cout << sizeof(S0);
cout << "\n\n";
cout << "Testing S1 ...\n";
cout << sizeof(S1) << endl;
S1 s1 = {'a', 0x22222222};
cout << sizeof(s1) << endl;
cout << &s1 << endl;
char *p1 = (char*)malloc(sizeof(char)*sizeof(s1));
memcpy (p1, &s1, sizeof(s1));
for (int i=0; i<sizeof(s1); i++)
printf ("%x ",*(p1+i));
cout << "\n\n";
cout << "Testing S2 ...\n";
cout << sizeof(S2) << endl;
S2 s2 = {0x22222222, 'a'};
cout << sizeof(s2) << endl;
cout << &s2 << endl;
char *p2 = (char*)malloc(sizeof(char)*sizeof(s2));
memcpy (p2, &s1, sizeof(s2));
for (int i=0; i<sizeof(s2); i++)
printf ("%x ",*(p2+i));
cout << "\n\n";
cout << "Testing S3 ...\n";
cout << sizeof(S3) << endl;
S3 s3 = {'b', s1, 'c'};
cout << sizeof(s3) << endl;
cout << &s3 << endl;
char *p3 = (char*)malloc(sizeof(char)*sizeof(s3));
memcpy (p3, &s3, sizeof(s3));
for (int i=0; i<sizeof(s3); i++)
printf ("%x ",*(p3+i));
cout << "\n\n";
return 0;
}
/*-------------------------------------------------------------------------------------------
Eclipse+CDT下运行结果:
Testing S0 ...
1
Testing S1 ...
8
8
0x22ff80
61 0 40 0 22 22 22 22
Testing S2 ...
8
8
0x22ff70
61 0 40 0 22 22 22 22
Testing S3 ...
16
16
0x22ff58
62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0
--------------------------------------------------------------------------------------------*/
总结规律发现:
在结构体中每个像出现char这样占一个字节的变量后面会自动补上3个字节,使之变为和int一样大小的4字节变量。 所以S1和S2就是占了8字节的内存,S3占了16字节的内存。
关于字节对齐:
查阅资料后发现,字节对齐有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
例如对S3来看:
S3中的S1其实是打散的int和char,所以相当是char,int,char,char,最长的宽度是int为4字节,所以要保证char也是占据4字节,所以最终就是总共16字节所示结果。
62 ffffffff 22 0 61 0 40 0 22 22 22 22 63 10 40 0。