关于内存对齐

老朋友pathuang68建议我了解一下结构体内存对齐的事儿,我就去了解了一番:

 

以下实验平台为 VC9。

 

这里先引出几条VC下结构体对齐的原则:

1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员自身大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员之后加上填充字节(trailing padding)。

第一条与第三条针对结构体视为一个整体对像来说的,第二条是针对结构体成员来说的。

至于为何第一条与第三条都要去考虑“最长类型”,是因为如果声明为结构体的数组的话,那么对于该数组的每一个元素的成员的访问都必须“对齐”,这也就是为何必须要考虑“最长类型对齐”的原因。

 

这里还有一个问题,

 

#pragma pack(push)
#pragma pack(n)
.....
#pragma pack(pop)

 

这些可以改变对齐状态,同样,在编译命令行里面设置 /Zpn 也可以改变对齐的状态。

 

如果这里的 n 与结构体内的“最长类型”不一致怎么办?

取最小的对齐,若n较小,则“最长类型”失效,以n为准。

 

所以,上三条原则听是针对默认的情况来说的,default情况下n为多少呢?肯定大于sizeof(double)。

 

还有一个问题,如果结构体内部有数组,怎么算?比如说 short fuck[5]; 数组将被视为连续存在的基本类型,而不被当成一个整体,比如说 fuck 将被视为 5 个 short ,而不是一个 short[5]。

 

记得微软有本书上说,“聪明”的VC会调整成员的顺序,使其整个结构体的大小最小,比如说:

大小将是 12 ,但若将 cf 调至最末一个成员,则大小将缩为 8。

但我今天拿 VC9 试了一把,好像满不是那么一回事儿!看来还真是“百见不如一闻”啊……

所以说,程序员在自己写STRUCT的时候,一定要注意成员的顺序问题。

 

下面我查了GCC的原则:

在GCC中,对齐模数的准则是:对齐模数最大只能是 4,也就是说,即使结构体中有double类型,对齐模数还是4,所以对齐模数只能是1,2,4。而且在上述的三条中,第2条里,offset必须是成员大小的整数倍,如果这个成员大小小于等于4则按照上述准则进行,但是如果大于4了,则结构体每个成员相对于结构体首地址的偏移量(offset)只能按照是4的整数倍来进行判断是否添加填充。

我对GCC不了解,还请对此了解的行家指正。

 

还有,C++还有一个类继承的问题,就是父子类的内存对齐怎么办呢?

http://blog.csdn.net/pathuang68/archive/2009/04/24/4106016.aspx

玄机逸士前辈的这篇博文里有说明。直接看结论就好了。

 

前辈有两个结论,

其一、C++ 语言保证“出现在 derived class 中的 base class suboject 有其完整性”;
其二、derived class 的对齐数 = min( 指定的全局对齐数,max( base class 的对齐数,derived class 的对齐数 ))

 

第一个结论没有问题。
第二个结论,需要修正一下,考虑如下情况:

输出是 6 和 11,若把NA和NB互换,则输出为 5 和 12。

这里面 6 和 5 是没问题的,关系在于派生类 B 的对齐怎么回事儿。

有人说 12 好理解,因为是 NB = 2 的整数倍,但问题在这儿,其实 B 在满足结论一的情况下的有效长度正是 6 + 5 = 11,它补了一位。

我的理解是,前辈的结论二可能是想证明父子类的对齐方式是相关的,而事实上,该例证明了,二者不相关,各按各的对齐方式来。

 

所以我将前辈的结论二拆成两个式子:

1.派生类的对齐数 = Sum (所有父类的对齐数) + 自身的对齐数;

2.类的对齐数  = Min (指定对齐数, 类成员最长字节数);

 

讨论完毕。

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值