C++ 结构体内存对齐

最近工作时需要用到内存对齐,查了资料。发现比较乱且观点不一,因此验证并总结。下面所写都是在实际中得到验证。

环境:XP,VC6.0.

内存对齐又称字节对齐,可以加快系统的处理速度。在结构体中的存储中尤其重要,那么系统对齐是按照什么方式呢?


每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。比如32位windows平台下,VC默认是按照8bytes对齐的(VC->Project->settings->c/c++->Code Generation中的truct member alignment 值默认是8),程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

这个是系统设置的对齐系数,实际的对齐系数是结构体的成员自身长度的最大值和系统设定系数的较小者。比较拗口,举例说明

struct strtest

{

char a;

short b

int c;

double d; 

};

对于这个结构体最大的成员长度是8(d),假设系统设定的是4,那么实际对齐系数就是4.如果没有成员c,d,那么实际对齐系数就是2.

下面所讲的都是针对实际对齐系数,简称N。

首先说一下结构体内存对齐规则:

1.结构体的首地址必须是N的整数倍。

2.对于每一个成员来说,相对首地址的偏移量必须是成员长度和N的较小者的倍数。

3.结构体的总大小必须是N的整数倍,不足后面进行补充。


下面就举例验证这3个规则:

#include<iostream.h>
typedef struct
{
char a;
short b;
int c;
double d;
char e[12];
}strTest1;


int main()
{
strTest1 test;
cout<<sizeof(char)<<sizeof(short)<<sizeof(int)<<sizeof(double)<<sizeof(test.e)<<sizeof(strTest1)<<endl;//基本数据类型所占
cout<<(int)&test.a<<endl;
cout<<(int)&test.b<<endl;
cout<<(int)&test.c<<endl;
cout<<(int)&test.d<<endl;
cout<<(int)&test.e<<endl;
cout<<(int)&test<<endl;


return 0;
}


其中系统设置对齐系数位4,运行结果如上图所示,首先测试了char,short,int,double,字符数组的长度以及整个结构体的长度。

在得到N之前先说一下数组,由于数组是在内存空间联系排列的,因此针对数组可拆成一个一个的基本类型看待。因此N=min(8,4)=4

结构体的首地址位1245028为4的倍数,首地址也是成员a的地址,成员b根据规则2所以首地址1245030-1245028=2(2/2=1),后面的成员以此按照规则2.

最后总大小位28是4的整数倍,因此不用补充。

如果系统设置对齐系数位8时,运行结果如下图所示


N=min(8,8)=8.首地址1245024是8的倍数。成员位置和上面分析类似,总大小位2+2+4+8+10=28不是8的倍数,因此补充为32.


上面说道数组作为结构体成员,如果是结构体变量作为成员呢?

规则4:结构体变量作为结构体的成员时,以整体看待。举例如下:

#include<iostream.h>


typedef struct 
{
char a;
int  b;
double c;
}strTest;
typedef struct
{
char a;
strTest b;
char c[12];
short d;
int e;
double f;
}strTest2;

int main()
{
strTest2 test2;


cout<<sizeof(char)<<sizeof(short)<<sizeof(int)<<sizeof(double)<<sizeof(strTest)<<sizeof(strTest2)<<endl;//基本数据类型所占
cout<<(int)&test2.a<<endl;
cout<<(int)&test2.b<<endl;
cout<<(int)&test2.c<<endl;
cout<<(int)&test2.d<<endl;
cout<<(int)&test2.e<<endl;
cout<<(int)&test2.f<<endl;
cout<<(int)&test2<<endl;


return 0;
}

其中系统设置对齐系数位8,运行结果如下


从结果可以看到strTest所占大小是16,这也符合我们上面的分析。N=min(16,8)=8

首地址1245000是8的倍数。第二个成员的大小是16大于8,按照8对齐,因此地址为1245008,cde比较好分析,f要注意规则2.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值