内存对齐原则:
1、结构体变量的首地址可以被其最宽基本类型成员大小与对齐基数中的较小者所整除;
2、结构体每一个成员相对于结构体首地址的偏移量(offset)都是该成员大小与对齐基数中的较小者的整数倍,若有须要编译器会在成员之间加上填充字节(internal adding);
3、结构体的总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,若有须要编译器会在最末一个成员以后加上填充字节(trailing padding)。ios
关于结构体分配内存和字节对齐原则
今天看到一个关于sizeof的使用问题,而且提到了计算机组成原理中的字节对齐,写了以下测试程序,发现了一些问题:ide
#include <iostream>
#include <malloc.h>
#include <stdlib.h>
using namespace std;测试
struct S0 {};spa
struct S1
{
char a;
int b;
};ip
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";it
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";io
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。 恩,搞移动开发对每一byte的内存都很珍惜啊~~~~~严重鄙视像Vista这样没干什么事就耗我七百多兆内存的系统。。