现象、问题描述
在做版本验证时,启动某跟踪,刚收到上报消息就异常退出。而其它类型的跟踪则能够正常进行。
关键过程、根本原因分析
调试代码,发现上报消息对应的数据结构不是1字节对齐。虽然这部分代码是上个版本新加的,但是上个版本没有问题,本版本对该数据结构也没有修改。怎么会出现此问题的?找到定义数据结构的头文件,
#pragma pack(1) //指定Align为 1
struct A_STRU {…… };
#pragma pack() //恢复缺省对齐格式
……
#pragma pack(1) //指定Align为 1
struct B_STRU{…… };
#pragma pack() //恢复缺省对齐格式
……
struct D_STRU{…… };
struct E_STRU{…… };
#pragma pack() //恢复缺省对齐格式
……
#pragma pack(1) //指定Align为 1
struct C_STRU{…… };
#pragma pack() //恢复缺省对齐格式
可以看到,数据结构D_STRU、E_STRU不是1字节对齐。查看clearcase上的修改记录,发现:尽管没有修改数据结构C_STRU,但是由于其它原因,将它挪到了文件尾,导致数据结构D_STRU、E_STRU不是1字节对齐。挪动前的定义应该是:
#pragma pack(1) //指定Align为 1
struct A_STRU {…… };
#pragma pack() //恢复缺省对齐格式
……
#pragma pack(1) //指定Align为 1
struct B_STRU{…… };
#pragma pack() //恢复缺省对齐格式
……
#pragma pack(1) //指定Align为 1
struct C_STRU{…… };
struct D_STRU{…… };
struct E_STRU{…… };
……
#pragma pack() //恢复缺省对齐格式
上面这段的代码的最大的隐患在于:作为本模块的唯一的头文件,既包括1字节对齐的数据结构,又包括4字节对齐的数据结构。所以,原来整个头文件中每个1字节对齐的数据结构都有一个#pragma pack(1)和#pragma pack()对定义。负责其它模块的同事因为不熟悉这种情况,新加蓝色部分的代码的时候,采用三个数据结构共用一个#pragma pack(1)和#pragma pack()对。这是第二个隐患。在这个1字节对齐和4字节对齐混杂的头文件中,移动其中任何一个数据结构,不小心都会导致问题出现。两个隐患,加上一个粗心的移动操作,移走
#pragma pack(1) //指定Align为 1
struct C_STRU{…… };
就导致了问题的发生。
当然,即使在这个时候,也还是可以避免版本验证的问题发生。如果在代码修改后,启动跟踪,接收一条消息,就能发现问题。所以,问题修改后,没有上实际环境验证,也是出问题的一大原因。
结论、解决方案及效果
给每个数据结构增加#pragma pack(1)和#pragma pack()对,就能够正常跟踪消息。
经验总结、预防措施和规范建议
要正确的使用1字节对齐。最好的方法是,1字节对齐的数据结构定义在一个单独的头文件中,与其它字节对齐方式的数据结构区分开来。这样,只用在文件头加上#pragma pack(1),文件尾加上#pragma pack(),就可以了。
如果在一个头文件中混用多种字节对齐方式,必须给每个1字节对齐的数据结构加上#pragma pack(1)和#pragma pack()对。千万不可图省事,几个数据结构共用一个#pragma pack(1)和#pragma pack()对。
再有,就是老生常谈的那句话,也是最重要的能够避免一切问题的基础,修改代码一定要细心,千万不可大意。修改完毕,一定要验证。
备注
无。
考核点
处理pack原则
试题
如下说法那些是错误的(D)
A: 需要加pack的地方一定要在定义结构的头文件中加,不要依赖命令行选项
B:在 #pragma pack(n) 后一定不要include其他头文件,若包含的头文件中改变了align值,将产生非预期结果
C: 在编写通信协议时,通信协议的帧结构;编写硬件驱动程序时,寄存器的结构,这两个地方都需要加pack1,即使看起来本来就自然对齐的,也要加pack,以免不同的编译器生成的代码不一样
D: 在混用多种字节对齐方式的头文件中,为了代码简洁,几个数据结构最好共用一个#pragma pack(1)和#pragma pack()对
E: 不要多人同时定义一个数据结构
阅读(460) | 评论(0) | 转发(0) |