记C++坑:3.结构体和类对齐补齐
背景:
项目从旧的编译器(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);
}
当然实际的项目中问题不会暴露的这么明显,当文件量很大,并且依赖嵌套很多的时候,这种问题其实是很难通过看代码发现的。
浪费了两天大好时光,记下来以供反思。
记C++坑:3.结构体和类对齐补齐相关推荐
- Swift 中枚举、结构体、类(enum、struct、class)
Swift 中枚举.结构体.类(enum.struct.class) Swift中的枚举与OC相比不会自动分配初始值,值的类型不会限定为整数,可以给定关联值类型和具体值(整型.浮点型.字符型(Swif ...
- Swift结构体与类
在面向过程的编程语言(如C语言)中,结构体用得比较多,但是面向对象之后,如在C++和Objective-C中,结构体已经很少使用了.这是因为结构体能够做的事情,类完全可以取而代之. 而Swift语言却 ...
- 结构体、类的成员对齐
自然对齐 为了保证CPU的运算稳定和效率,要求基本数据类型在内存中的存储地址必须自然对齐.所谓自然对齐,就是基本数据类型的变量不能简单的存储于内存中的任意地址处,它们的起始地址必须能够被它们的大小整除 ...
- 详解结构体、类等内存字节对齐
先说个题外话:早些年我学C程序设计时,写过一段解释硬盘MBR分区表的代码,对着磁盘编辑器怎么看,怎么对,可一执行,结果就错了.当时调试也不太会,又根本没听过结构体对齐这一说,所以,问题解决不了,好几天 ...
- C++:C++语言入门级基础知识考察点回顾之函数、结构体和类
C++:C++语言入门级基础知识考察点回顾之函数.结构体和类 目录 C++的函数 1.函数的定义.调用,全局变量局部变量 1.1.自定义函数求其倒数
- c#中结构体和类的比较
前几天,有位同学问我它们用起来有什么区别,当时也不大清楚,糊弄过去了,但是,人不能自欺欺人,不能连自己的无知也要糊弄! 翻了下书,总结一下. 区别: 结构是一种用关键字struct声明的自定义数据类型 ...
- 结构体和类的区别-Objective-C基础
1 结构体 与类的相同点 都可以将多个数据封装为1个整体 struct Date{ int year; int month; int day; } @interface Date :NSObject ...
- swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)
在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换.我们可以先看看官方文档的描述: Unlike other programming languages, Swift does ...
- C++工作笔记-结构体与类的进一步探究(在C++中的结构体,非C语言结构体)
今天把Qt Creator中的项目放到VS上,使用MSVC编译器发现跑不动链接错误,报的是如下的这个错误: 我在Qt上用MinGW明明不会报错,而他却说链接不到,日了个狗. 后面根据报错提示,我把如下 ...
- Go 系列教程 —— 26. 结构体取代类
欢迎来到 Golang 系列教程的第 26 篇. Go 支持面向对象吗? Go 并不是完全面向对象的编程语言.Go 官网的 FAQ 回答了 Go 是否是面向对象语言,摘录如下. 可以说是,也可以说不是 ...
最新文章
- 刚刚,2021QS美国大学排名发布!哈佛,斯坦福,MIT位列前三
- Luogu P4782 【模板】2-SAT 问题(2-SAT)
- linux centos6.5 网络配置
- 中英文论文高效排版插件一一 Tip ( Text Image P rocessing )
- CodeSmith 基础用法和例子
- jclouds的命令行界面
- 天池 在线编程 有序队列
- cassss服务未启动_电梯启动死机故障处理方法
- osg学习笔记(一)
- cmos存储器中存放了_天津大学姚建铨院士,张雅婷副教授JMCC:具有宽光谱调控特性的阻变存储器...
- relativelayout中按键不能点_CNC | M80/M800系列系统常见按键和外部存储器故障
- golang结构体tag的使用
- php rtc,php – webRTC与本地网络
- PTA4-11 先序输出叶结点
- Kubernetes之StatefulSet
- 每一句都值得品味的话
- 机器学习课程笔记【三】广义线性模型(2)-构建广义线性模型
- JAVA语言基础——类型转换
- 如何成为成功的Andr​​oid游戏开发
- android shell强制删除文件夹_Windows 强制删除文件及文件夹命令