关于C++中由于字节对齐引起内存问题定位分析

 更新时间:2021年06月10日 09:54:45   作者:wingrez  
前几天遇到一个稀奇古怪的问题,在创建对象的时候程序异常退出,查找代码发现结构体数组问题,最终把问题简化得到解决方法,下面小编把我的问题及解决方案分享到脚本之家平台供大家参考下

最近遇到了一个奇怪的问题,在创建对象时程序异常退出,具体地,在构造函数中访问类中最后一个成员变量时,程序异常退出。

问题定位

查看代码,发现该类中有一个结构体数组,该结构体在类的外面声明,用 #pragma pack(push,1) 设置了一字节对齐方式,而类不在这个作用范围内,所以是按照默认字节对齐方式的。怀疑该问题是因为,类的字节对齐方式和类中的结构体字节方式不同引起的。但这从理论方面解释不通。

继续定位,在创建对象之前用sizeof打印类的大小,再在类的构造函数中打印类的大小。发现这两个大小居然不同。这证实了的确与字节对齐有关,创建对象之前和在构造函数中,两边选择的字节对齐方式不同,导致计算类的大小不同。

但是为什么这两个地方的字节对齐方式不同呢?

当把该类也使用 #pragma pack(push,1) 设置字节对齐方式之后,类的大小又变得相同了。大胆猜测,由于 #pragma pack(push, 1) 是一种栈的结构,可能有某个文件中,设置了字节对齐方式之后,没有用 #pragma pack(pop) 恢复。

查找全局文件,的确找到了一个文件存在这样的问题,当把 #pragma pack(pop) 后加上后,问题解决。

问题模型

我将这个问题简化成下面这样,可以帮助大家更好地理解。
CA.h,CA类的声明,模拟只push,没pop的文件

#ifndef CA_H
#define CA_H

#include <iostream>
using namespace std;

#pragma pack(push, 1)

class CA {
    int a;
    char b;
};

#endif

CB.h,CB类的声明。St结构体设置一字节对齐方式,CB类使用默认字节对齐方式。

#ifndef CB_H
#define CB_H

#include <iostream>
using namespace std;

#pragma pack(push,1)

struct St {
    int a1;
    int a2;
    int a3;
    char a4;
    char a5;
};

#pragma pack(pop)

class CB {
public:
    CB();
    int a1;
    int a2;
    int a3;
    char a4;
    char a5;
    St a6[10];
    bool a7;
};

#endif

CB.cpp,CB类的实现。

#include "CB.h"
#include <iostream>

using namespace std;

CB::CB()
{
    cout << "constructor: sizeof(CB) = ";
    cout << sizeof(CB) << endl;
}

main.cpp,用于创建CB对象

#include "CA.h"
#include "CB.h"
#include <iostream>

using namespace std;

int main()
{
    cout << "main: sizeof(CB) = ";
    cout << sizeof(CB) << endl;
    CB *pCB = new CB;
}

编译上述文件并执行,可以得到下面的结果:

main: sizeof(CB) = 155
constructor: sizeof(CB) = 156

可以看到,两处计算的类的大小是不同的。在main函数里,分配了155字节的空间,而在构造函数中却认为有156字节的空间,当访问最后一字节时,程序出现了踩内存。

问题分析

为什么main.cpp和CB.cpp认为CB的字节对齐方式不同呢?
这主要还是因为main.cpp包含了CA.h,CA.h在main.cpp中展开,CB.h也展开,CA.h中设置的一字节对齐方式,影响到了CB类的声明,当编译main.cpp时,CB使用一字节对齐方式。

而CB.h没有包含CA.h,当编译CB.cpp时,并没有受到CA.h的影响,CB使用默认字节对齐方式。

以上就是关于C++中由于字节对齐引起内存问题定位分析的详细内容,更多关于c++字节对齐内存问题的资料请关注脚本之家其它相关文章!

相关文章

  • C语言各种符号的使用介绍上篇

    C语言各种符号的使用介绍上篇

    C 语言的基本符号就有 20 多个,每个符号可能同时具有多重含义,而且这些符号之间相互组合又使得 C 语言中的符号变得更加复杂起来
    2022-08-08
  • Qt的Qss用法小结

    Qt的Qss用法小结

    Qt的Qss是一种用于定义用户界面的样式表语言,本文主要介绍了Qt的Qss用法小结,非常具有实用价值,需要的朋友可以参考下
    2023-06-06
  • C语言system 自动关机函数代码

    C语言system 自动关机函数代码

    这篇文章主要介绍了C语言system 自动关机函数代码,需要的朋友可以参考下
    2016-04-04
  • C++中关于constexpr函数使用及说明

    C++中关于constexpr函数使用及说明

    这篇文章主要介绍了C++中关于constexpr函数使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • 用C语言程序判断大小端模式

    用C语言程序判断大小端模式

    本文介绍了用C语言程序判断大小端的方法,与大家分享一下。
    2013-04-04
  • Pipes实现LeetCode(194.转置文件)

    Pipes实现LeetCode(194.转置文件)

    这篇文章主要介绍了Pipes实现LeetCode(194.转置文件),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • C语言实现简单的图书管理系统

    C语言实现简单的图书管理系统

    这篇文章主要为大家详细介绍了C语言实现简单的图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • C++ Boost Format超详细讲解

    C++ Boost Format超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • MFC修改编辑框光标显示位置方法详解

    MFC修改编辑框光标显示位置方法详解

    这篇文章主要介绍了在MFC中利用CComboBox控件修改编辑框光标显示位置的两种解决方法,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-02-02
  • C 语言基础教程(我的C之旅开始了)[四]

    C 语言基础教程(我的C之旅开始了)[四]

    C 语言基础教程(我的C之旅开始了)[四]...
    2007-02-02

最新评论