C++内存布局

2023-12-19

温故而知新,本文浅聊和回顾下C++内存布局的知识。

一、c++内存布局

C++的内存布局主要包括以下几个部分:

  • 代码段 :存储程序的机器代码。
  • . 数据段 :存储全局变量和静态变量。数据段又分为初始化数据段(存储初始化的全局变量和静态变量)和未初始化数据段(存储未初始化的全局变量和静态变量)。
  • :用于动态内存分配。当你使用new或malloc函数时,内存会从堆中分配。
  • :用于存储局部变量和函数调用的信息(例如返回地址和参数)。当你调用一个函数时,一个新的栈帧会被压入栈,当函数返回时,这个栈帧会被弹出。
  • 常量段 :存储常量字符串和其他常量。

代码示例

#include <iostream>

int global_var = 0;  // 初始化的全局变量,存储在初始化数据段
int uninit_global_var;  // 未初始化的全局变量,存储在未初始化数据段

void foo() {
    int local_var = 0;  // 局部变量,存储在栈
    static int static_local_var = 0;  // 静态局部变量,存储在初始化数据段
    int* dynamic_var = new int(0);  // 动态分配的内存,地址在堆,dynamic_var指针变量的生命周期是foo函数栈

    std::cout << "local_var: " << &local_var << std::endl;
    std::cout << "static_local_var: " << &static_local_var << std::endl;
    std::cout << "dynamic_var: " << dynamic_var << std::endl;

    delete dynamic_var;  // 释放动态分配的内存
}

int main() {
    std::cout << "global_var: " << &global_var << std::endl;
    std::cout << "uninit_global_var: " << &uninit_global_var << std::endl;

    foo();

    return 0;
}

二、C++ 类的内存布局

C++类的内存布局主要取决于类的数据成员和继承关系。以下是一些基本的规则:

  • 数据成员变量 :类的数据成员按照它们在类定义中的顺序存储在内存中。每个数据成员的偏移量是它的类型对齐要求的倍数。
// x64
#pragma pack(push,4) //指定4字节对齐
class TmpClass{}; // 空类sizeof,大小为1

class NoVirtual
{
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};
#pragma pack(pop) 
  • 成员函数 :在C++中,成员函数并不直接存储在每个对象中。相反,所有对象共享同一个成员函数的副本。成员函数的代码存储在 代码段 ,而不是每个对象的内存空间。因此,成员函数不影响类的 sizeof 大小。
    当你调用一个对象的成员函数时,编译器会自动将对象的地址作为隐藏参数传递给成员函数。这个隐藏参数通常被称为this指针。通过this指针,成员函数可以访问调用它的对象的数据成员。
class NoVirtual
{
    void dc(){}	// 成员函数,内存在代码段
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};
  • 静态成员变量 :静态成员变量不属于类的任何一个对象,它们在所有对象之间共享。静态成员变量存储在全局数据段,而不是对象的内存空间。

  • 静态成员函数 :静态成员函数也不属于类的任何一个对象。它们没有this指针,因此不能访问类的非静态成员。静态成员函数的地址存储在代码段。

  • 继承 :如果一个类继承自一个或多个基类,那么基类的数据成员会先于派生类的数据成员存储在内存中。如果有多个基类,那么基类的数据成员按照它们在类定义中的顺序存储。

class Iface
{
public:
    Iface(){MYTRACE();}
    virtual ~Iface(){MYTRACE();}
    virtual void Ifun() = 0;
};


// 继承
class MemLayout : public Iface
{
public:

    MemLayout(){ MYTRACE(); }
    ~MemLayout(){ MYTRACE(); }

    virtual void Ifun() override { MYTRACE(); }

    virtual void dc0(){ MYTRACE(); }
    virtual void dc1(){ MYTRACE(); }

private:
    int m_num = 0;
    static std::string m_desc;
};

std::string MemLayout::m_desc = "hello";

在这里插入图片描述

  • 虚函数 :如果一个类有虚函数( virtual 关键字修饰),那么编译器会为这个类生成一个虚函数表( vtable : 函数指针数组),并在每个对象中添加一个指向虚函数表的指针( vptr )。虚函数表中存储了虚函数的地址。如果一个类继承自一个有虚函数的基类,那么它会继承基类的虚函数表。
class VirtualClass
{
   virtual  void dc(){}
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};

在这里插入图片描述

  • 虚继承 :如果一个类使用虚继承,那么编译器会为这个类生成一个虚基类表( vbtable ),并在每个对象中添加一个指向虚基类表的指针。虚基类表中存储了虚基类的偏移量。 直白点说,虚继承的派生类的实例化对象,可是唯一指向了两张虚函数表的(下面有图为证)~
    请添加图片描述
class NoVirtual
{
    void dc(){}
public:
    int m_i;    // 4字节
    double m_d; // 8字节
    shared_ptr<int> m_ptr; // 8字节 ==》64bit system ;4字节 ==》 32bit system
};

class Iface
{
public:
    Iface(){MYTRACE();}
    virtual ~Iface(){MYTRACE();}
    virtual void Ifun() = 0;
};

// 虚继承
class MemLayout : virtual public Iface
{
public:

    MemLayout(){ MYTRACE(); }
    ~MemLayout(){ MYTRACE(); }

    virtual void Ifun() override { MYTRACE(); }

    virtual void dc0(){ MYTRACE(); }
    virtual void dc1(){ MYTRACE(); }

private:
    int m_num = 0;
    static std::string m_desc;
};

std::string MemLayout::m_desc = "hello";

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++内存布局 的相关文章

  • 更新面板工作速度非常慢

    我正在编写一个用户可以注册的应用程序 注册时 可以选择多个选项 并根据这些注册字段可见或不可见以及是否必需 我想出了一个想法 所有字段都将位于 updatePanel 中 当用户更改注册选项时 我将在服务器端设置这些字段的可见性 它可以工作
  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • 使用 CMake 时如何导出 Emscripten 中的 C 函数

    In 本教程 https emscripten org docs porting connecting cpp and javascript Interacting with code html interacting with code
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 按扩展名过滤搜索文件返回太多结果

    我正在开发一个 C 控制台应用程序 它必须管理 Windows 操作系统上的文件 我需要获取具有特定扩展名的文件名 列表 我找到了很多解决方案 最建议的是以下一种 HANDLE hFind WIN32 FIND DATA data hFin
  • 现代 C++ 编译器是否能够在某些情况下避免调用 const 函数两次?

    例如 如果我有以下代码 class SomeDataProcessor public bool calc const SomeData d1 const SomeData d2 const private Some non mutable
  • java中如何重新初始化int数组

    class PassingRefByVal static void Change int pArray pArray 0 888 This change affects the original element pArray new int
  • 如何使用 Regex.Replace 从字符串中删除数字?

    我需要使用Regex Replace从字符串中删除所有数字和符号 输入示例 123 abcd33输出示例 abcd 请尝试以下操作 var output Regex Replace input d string Empty The d标识符
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 在 C# 中检查 PowerShell 执行策略的最佳方法是什么?

    当你跑步时Get ExecutionPolicy在 PowerShell 中 它得到有效的执行政策 https learn microsoft com en us powershell module microsoft powershell
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 将 Word 转换为 PDF - 禁用“保存”对话框

    我有一个用 C 编写的 Word 到 PDF 转换器 除了一件事之外 它工作得很好 有时 在某些 Word 文件上 后台会出现一条消息保存源文件中的更改 gt 是 否 取消 但我没有对源文件进行任何更改 我只想从 Word 文件创建 PDF
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • C++ 对象用 new 创建,用 free() 销毁;这有多糟糕?

    我正在修改一个相对较大的 C 程序 不幸的是 并不总是清楚我之前的人使用的是 C 还是 C 语法 这是在一所大学的电气工程系 我们 EE 总是想用 C 来做所有事情 不幸的是 在这种情况下 人们实际上可以逃脱惩罚 但是 如果有人创建一个对象
  • 我可以使用 lambda 函数或 std::function 对象来代替函数指针吗?

    我有一个需要使用的库 它定义了以下内容 typedef void CallbackFunction const int i 并且有一个注册回调的函数 如下所示 void registerCallback CallbackFunction p

随机推荐

  • 制造行业CRM选型:好用的系统有这五大优势

    制造业CRM管理系统的线索 订单 销售 营销功能都在制造业务环节中起着重要作用 制造业CRM系统有什么好处 制造业CRM的五大优势 在团队协作优化销售策略等方面都发挥着重要作用 一 提高线索利用率 功能 线索管理 CRM系统助力企业梳理整合
  • 3DM/PLY格式在线转换

    3D模型在线转换 https 3dconvert nsdt cloud 是一个可以进行3D模型格式转换的在线工具 支持多种3D模型格式进行在线预览和互相转换 3DM与PLY格式简介 3DM是一种常用的三维模型文件格式 具有多种几何体和材质
  • 自动化测试-数据生成工具

    为什么开发ZenData ZenData帮助文件 ZenData测试数据生成器 ZenData通用数据生成工具 ZenData官网 ZenData是一款无依赖 跨平台 语法简单 使用方便的通用数据生成工具 其主要两大功能 数据生成和数据解析
  • 3DM/DAE格式在线转换

    3D模型在线转换 https 3dconvert nsdt cloud 是一个可以进行3D模型格式转换的在线工具 支持多种3D模型格式进行在线预览和互相转换 3DM与DAE格式简介 3DM是一种常用的三维模型文件格式 具有多种几何体和材质
  • 高速风筒方案中的共膜电感--【其利天下技术】

    我们知道 高速吹风筒的电源采用的是日常我们用的市电 市电是高压交流电源 所以高压电路的噪声是比较大的 为了使产品符合安规要求 我们的电路设计必须要符合安规设计 所以这也是高速吹风筒为什么要加安规电容和共模电感的主要原因 那么什么是共膜电感呢
  • 各种不同语言分别整理的拿来开箱即用的8个开源免费单点登录(SSO)系统

    各种不同语言分别整理的拿来开箱即用的8个开源免费单点登录 SSO 系统 单点登录 SSO 是一个登录服务层 通过一次登录访问多个应用 使用SSO服务可以提高多系统使用的用户体验和安全性 用户不必记忆多个密码 不必多次登录浪费时间 下面推荐一
  • 智能问询机器人:引领人机交互新时代

    随着科技的迅猛发展和人工智能的广泛应用 智能问询机器人正逐渐成为人们生活中不可或缺的一部分 智能问询机器人能够通过自然语言处理和机器学习等技术 与用户进行智能化的对话交互 帮助解决问题 提供信息和服务 本文将探讨智能问询机器人的发展历程 应
  • 为什么多片DDR菊花链拓扑连接时末端需要接很多的电阻

    大家如果做过DDR的设计可能会发现在进行多片DDR连线时 通常在信号的末端会放置很多的电阻 如下图所示 那么这些电阻都是起什么作用的呢 通常在DDR末端的电阻是为了防止信号反射的 起阻抗匹配的作用 之前我们介绍过另一种防止信号反射的解决措施
  • AttributeError: module ‘IPython.utils.traitlets‘ has no attribute ‘Unicode‘

    format type traitlets Unicode JAVASCRIPT MODULE MIME TYPE AttributeError module IPython utils traitlets has no attribute
  • input file文件限制上传类型

    1
  • Redis哨兵模式yaml文件连接配置

    备忘录 SpringCloud或者SpringBoot连接Redis哨兵模式集群 启动会报 Cannot retrieve initial cluster partitions from initial URIs 错误 现在整理Redis连
  • H5 模块化下调取外部链接js脚本方法

    div class anniu div
  • 全面掌握XSS漏洞攻击,实战案例从Self-XSS到账户接管,以及通过参数污染的XSS实现攻击

    全面掌握XSS漏洞攻击 实战案例从Self XSS到账户接管 什么是跨站脚本攻击 XSS 跨站脚本攻击 XSS 是一种网络安全漏洞 允许攻击者破坏用户与易受攻击的应用程序之间的交互 它允许攻击者绕过同源策略 该策略旨在将不同的网站隔离开来
  • QtForAndroid-------Qt开发Android程序的环境搭建

    1 Qt 我用的是Qt5 14版本的 其他的版本不知道 搭建Android的开发环境前提条件 Java SDK Android SDK Android NDK 另外在安装QT时需要把这个选项勾上 低版本的Qt可能是这样的 具体的安装步骤我是
  • IDEA--properties配置文件中文乱码处理

    在setting配置中进行配置
  • 解读 | VR体验式教育的优势 让教育触手可及

    大家好 我是极智视界 欢迎关注我的公众号 获取我的更多前沿科技分享 邀您加入我的知识星球 极智视界 星球内有超多好玩的项目实战源码和资源下载 链接 https t zsxq com 0aiNxERDq 很多孩子过多地沉浸在所谓的 传统教育
  • 极智AI | 算子融合、矩阵分块 一图看懂大模型优化技术FlashAttention

    欢迎关注我的公众号 极智视界 获取我的更多经验分享 大家好 我是极智视界 本文来介绍一下 算子融合 矩阵分块 一图看懂大模型优化技术FlashAttention 邀您加入我的知识星球 极智视界 星球内有超多好玩的项目实战源码下载 链接 ht
  • 数组对象排序 (arr.sort())

    前端面试题库 面试必备 推荐 地址 前端面试题库 对象排序 arr sort 描述 方法sort 将在原数组上对 数组元素 进行排序 即排序时不创建新的数组副本 如果想按照别的顺序进行排序 就必须提供比较函数 该函数要比较两个值 然后返回一
  • WIN10安装gurobi给matlab使用(记录)

    https www gurobi com downloads gurobi software 这是以前的matlab路径 需要修改成新的 使用校园网激活一下 运行gurobi setup Google报错信息 发现mathwork官方的解释
  • C++内存布局

    温故而知新 本文浅聊和回顾下C 内存布局的知识 一 c 内存布局 C 的内存布局主要包括以下几个部分 代码段 存储程序的机器代码 数据段 存储全局变量和静态变量 数据段又分为初始化数据段 存储初始化的全局变量和静态变量 和未初始化数据段 存