管理好你C++项目中的结构对齐

最近把一个VC6.0的项目升级到VC2008,主要是有点厌倦了VC6那冷冰冰的古老面孔,想换点新鲜感。顺便说一下,项目中使用了Notes API C库来实现邮件的访问。重新编译

并不像想象中的那么困难重重,无非就是修正了一些字符串转换方面的warning和error。编译完成后,随手打开CppUnit准备测试,砰,一个错误对话框跳出:

Run-Time Check Failure #2 - Stack around the variable 'xxx' was corrupted.

错误是由一个字符串变量引起的,该变量是一个自定义类CNString的实例。按照MSDN上的说法,这个对象引起了堆栈泄露。

为了找到问题的原因,把CNString做了一个精简,只保留构造和析构函数:

重新做了一个很简单的测试:

  

运行,错误依旧。关掉了VC2008的RTC检查,错误消失。不能轻易放弃,一定有问题。一般的堆栈内存泄露错误都是因为数组越界访问。可是,我的代码就是一个简单的new和delete操作。可是问题到底在哪呢?

在google了搜寻了好久,在CSDN的博客上找到free2o一篇关于security cookie的文章:

http://blog.csdn.net/free2o/archive/2008/06/20/2570168.aspx,其中关于_RTC_CheckStackVars的函数部分引起了我的注意。经过对汇编代码的反复推敲和琢磨,我发现了问题的真正原因。

首先,编译器在函数调用前分配一个0E4h大小的堆栈空间,并使用0CCCCCCCCh填充堆栈:

  

在函数完成后,编译器检查未使用的堆栈部分是否被破坏:

其中,472B00h内存空间存放的是_RTC_framedesc结构内容,其中保存了堆栈中变量的地址、大小、名称等信息:

01 00 00 00 08 2b 47 00 e0 ff ff ff 0a 00 00 00 14 2b 47 00 73

注意:上面的01表示变量的数量,0e表示的是变量的大小。发现问题了吗?我的类定义中只有char*, WORD, wchar_t*三个成员变量,按照默认的/ZP8对齐方式,应该大小是0c(12)才对,怎么是0a(10)了?这样,当运行时检查str变量后面的堆栈空间时,内存寻址出现错误,把正常的对象空间当成了未使用空间来检查,因此,砰!你中奖了。

有了这样的认识,我立即开始检查头文件中关于结构对齐的设置。终于,在notes c API的global.h中,发现了如下行:

#pragma pack(1)

记得之前在notes c API的帮助中看到关于Data Structure Packing的部分,还颇不以为然,这回彻底顿悟了。

On machines that use the Intel architecture, data structures passed through the Lotus C API for Domino and Notes must have the structure members packed on 1-byte boundaries. This saves space in data structures stored on disk, and preserves binary compatibility with previous releases of Domino or Notes. 

因为,我在项目中并没有使用需要传递结构的Lotus API函数,因此,在测试类头文件中加上:

#pragma pack()

问题立即解决。

接着运行另一个测试,发现XML又无法加载,总是提示“无法识别的XML头”。XML的数据是通过一个结构指针传入的:

检查config里的数据,都是正确的,到底是怎么回事?难道还是对齐问题?

通过在创建结构数据的cpp和加载xml的cpp中加入以下指令:

#pragma pack(show)

 

编译后发现,两个cpp的结构对齐方式一个是1,一个是8。原来,前者包含了global.h头文件,后者没有包含。果真是结构对齐的问题,解决办法是在结构定义前后定义pack指令:

 

问题解决。

 

 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值