记C++坑:3.结构体和类对齐补齐

来源:互联网 发布:南通软件开发公司 编辑:程序博客网 时间:2024/06/01 13:21

背景:

项目从旧的编译器(VC6)移植到新编译器(VS2015)。

移植过程中有很多的编译错误连接错误都一一解决之后,运行,发现崩溃,错误为声明一个类类型对象变量时候堆栈错误。导致出现内存问题。因为是移植项目,原来的编译器编译的版本跑起来好好的,所以没太怀疑时代码问题,最开始的思考思路一直集中在是不是使用的lib库有问题,检查项目配置,检查各个库的版本,都没有什么发现,后来再来看代码,发现真的就是代码问题,对同一个类型声明的头文件应用的不同cpp中对这个类使用sizeof,发现得到的结果居然不一样。。

所以导致这个堆栈损坏的问题的原因就是因为两边认为的类型的大小不一致,导致交互的时候内存越界了。

而引起问题的最根本原因时原来的代码中

#pragma pack 

的使用不规范。

顺便在这个重温一下使用规则,一般在涉及到需要作为数据传递类型的数据结构定义的时候要指定对齐方式,将定义包含在其中,保证不同模块之间数据交互的正确性。

例如:

#pragma pack(push, 1)typedef tag_S{char m_1;int m_2;double m_3;char m_4[5];};#pragma pack(pop)
还有不同的写法:
#pragma pack(1)//...#pragma pack()
这种写法的问题在于如果之前指定了一种或多种对齐方式,在这段代码之后,这种/些对齐方式将被取消,并还原成默认对齐方式,所以推荐使用push和pop

在代码中还遇到以下存在bug的写法:

#pragma pack(push, 1)//...#pragma pack(pop, 1)
看似pop了,但是在pop的同时又指定了按照1字节对齐,所以是有bug的。


下面来说说为什么不这样写会出问题。

首先,当你写的类型是用在不同的程序间来传递数据的,那么不同bit程序默认对齐方式不一致,就导致了数据交互的bug。

当然,在同一个程序中也可能会出现bug。就比如我遇到的。

上一段简单的代码:

StructDef.h

#pragma oncestruct S{char m_1;int m_2;double m_3;char m_4[5];};
UserCpp1.cpp
#pragma pack(push,1)#include "StructDef.h"#pragma pack(pop)int GetS_size_1(){return sizeof(S);}
UserCpp2.cpp
#pragma pack(push,4)#include "StructDef.h"#pragma pack(pop)int GetS_size_2(){return sizeof(S);}

当然实际的项目中问题不会暴露的这么明显,当文件量很大,并且依赖嵌套很多的时候,这种问题其实是很难通过看代码发现的。

浪费了两天大好时光,记下来以供反思。

0 0
原创粉丝点击