同事在使用第三方sdk时,总是不能获取正确的结果,但是验证第三方提供的demo又是可以成功获取的,同样的SDK为什么会导致不同的结果?。同事几天调试未果于是找到我,问我有没有遇到过这个问题。
先说下该数据结构体类型 64 + 4 + 4 + 4 + 8 + 8,出问题的地方在最后两个参数,这里前一个参数作A(64位),后一个参数作B(64位),在调用函数之前有个赋值操作
int_64 = int_32; 这里把给A赋值的变量名称作C(32位),给B赋值的变量名称作D(32位)。
当时看到同事已经做了打印,调用函数前打印A,B的值都没有问题,但是被调用函数内部打印的A,B的值不正常。打印的是用十进制,没有看出端倪,让同事改成十六进制显示,发现一个问题,A里的值是D的值向左偏移32位获得的值(oxD0000),B里的值看不到规律。
该程序是在VC环境中编译的,使用小端模式,这里以左边为低地址,右边为高地址,AB应该在被调用的函数理解为
但是实际打印结果来看在被调用函数理解成了
即向右偏移了四个字节.
这里就开始怀疑字节对齐的问题了,但是查看两个程序(同事的程序和demo程序)使用的字节对齐方式都是默认对齐,都是8字节对齐。为什么同样方式的字节对齐结果不对?当时还是坚持了认定是字节对齐问题,分别又打印了结构体的sizeof,结果同事的程序是92,demo程序是96. 后来查问题遇到了瓶颈,为了同事顺利测试程序,让其在
A参数前面增加了一个4字节变量,此时结构体内容为 64 + 4 + 4 + 4 + 4 + 8 + 8, 函数可以获取结果了。
后来就思考按照8字节对齐方式,原结构体应该长度为96的,现在为92,说明没有起作用,然后按照没起作用的思路找到在使用这个第三方sdk头文件之前还包含了另外多个客户的sdk头文件,而恰恰这些头文件中有的定义了#pragma pack(4), #pragma pack(1), 覆盖了编译器设置的对齐选项。 至此所有问题都有了答案,最终该问题解决方式是在这个第三方sdk头文件中加入#pragma pack(8)。
如何能避免类似的问题呢,如何限定#pragma pack(N)的范围暂时还没有想到方法,范围问题可以联想到不同类型变量的生命周期与namespace,程序设计时应尽量减少一个设置对其他单元的影响。