C++类对象内存对齐方式

news2025/1/5 17:14:34

文章目录

      • 一、基本概念
      • 二、对齐规则
      • 三、编译器控制对齐

在C++中,类的内存对齐方式遵循以下一些原则和特点:

一、基本概念

内存对齐(Memory Alignment)也叫字节对齐,是指数据在内存中的存放地址要满足一定的规则,通常是按照数据类型自身的对齐模数来进行对齐放置。这样做的主要目的是为了提高处理器访问内存的效率,因为处理器在读取内存时往往按照字长(比如32位系统按4字节,64位系统按8字节)等单位进行读取,合适的对齐能让数据一次性被完整读取,减少读取次数。

二、对齐规则

  1. 数据成员对齐
    对于类中的各个数据成员,编译器会按照它们各自类型对应的对齐要求来安排内存位置。常见基本数据类型的对齐要求如下:
    • char类型:通常按1字节对齐,也就是说char类型的数据可以存放在任意内存地址上,因为任何地址对于1字节的访问都是对齐的。
    • short类型:一般按2字节对齐,意味着short类型的数据的存储地址应该是2的倍数(例如在内存地址0、2、4等位置)。
    • int类型:多数情况下按4字节对齐,其存储地址需是4的倍数(像内存地址0、4、8等)。
    • double类型:常按8字节对齐,存储地址要是8的倍数(例如内存地址0、8、16等)。

例如,有这样一个类:

class AlignmentExample {
    char c;
    int i;
    short s;
};

按照对齐规则,首先char类型的c可以存放在任意地址(假设起始地址为0),然后int类型的i由于要按4字节对齐,所以它会从地址4开始存放(因为前面的c占了1字节,填充3字节使其对齐到4字节边界),最后short类型的s按2字节对齐,它会接着存放在地址8处(因为地址4 - 7被i占用了,地址8刚好满足2字节对齐要求)。整个类对象的大小可能会是10字节,但考虑到内存对齐,编译器通常会填充到12字节,使得下一个对象(如果有连续存放的情况)也能按照合适的对齐要求来放置。

  1. 继承情况下的对齐
    在继承关系中,派生类对象的内存布局会先包含基类的数据成员,并且遵循基类原有的对齐方式以及整个继承体系下的综合对齐要求。

比如:

class Base {
    int baseNum;
};

class Derived : public Base {
    short derivedNum;
};

Derived类对象的内存中,先是Base类的baseNum按4字节对齐存放,然后Derived类的short类型的derivedNum按2字节对齐存放在合适位置(在baseNum之后,且满足2字节对齐要求)。

  1. 结构体(类)整体对齐
    一个类或者结构体整体的大小也需要满足其内部最严格的对齐要求。也就是说,类或结构体的总大小应该是其内部最大对齐模数(通常是最大数据类型对应的对齐字节数)的整数倍。例如,如果一个类中有int(按4字节对齐)和double(按8字节对齐)类型的数据成员,那么这个类整体的大小要为8的倍数,编译器会在必要时填充一些字节来达到这个要求。

三、编译器控制对齐

  1. 指定对齐方式(以#pragma pack为例)
    可以通过编译器指令来改变默认的对齐规则,比如在一些编译器中使用#pragma pack指令。

例如:

#pragma pack(1)
class PackedClass {
    char c;
    int i;
    short s;
};
#pragma pack()

#pragma pack(1)表示设置按照1字节对齐,此时PackedClass类对象就不会有额外的填充字节来满足其他对齐要求了,它的大小就是char(1字节) + int(4字节) + short(2字节) = 7字节。而#pragma pack()用于恢复编译器的默认对齐设置。

不同的编译器可能还支持其他方式来指定对齐参数,比如有些编译器可以使用特定的编译选项来全局设置对齐规则等。

  1. 属性指定(部分编译器支持)
    有些编译器允许通过属性(Attributes)来指定类或者数据成员的对齐方式,例如在某些支持特定扩展的C++编译器中,可以像下面这样做:
class __attribute__((aligned(8))) AlignedClass {
    // 类中的数据成员
};

上述代码通过__attribute__((aligned(8)))属性指定AlignedClass类按照8字节对齐,类中的数据成员以及整体的大小都会遵循这个8字节对齐的要求来布局和确定。

总之,C++类的对齐方式是综合考虑数据成员类型、继承关系以及编译器相关设置等多方面因素的,合适的对齐有助于提升程序运行时内存访问的性能。

1、结构体大小由成员变量和偏移量相加而成;
2、其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处,整体大小也要能被对齐数整除

总对齐数: = 编译器默认的一个对齐数与该成员大小的较小值, 也就是min{编译器默认的对齐数, 成员变量大小的最大值},VS中默认的对齐数为8;

单个对齐数:该类型变量所占内存大小,char 对齐数是1 ,int 对齐数是4 , double 是8 , 32位指针类型是4 , 64位指针类型是8;

对齐原则分两步:
1、单个成员变量对齐(也就是说,单个变量的起始地址能被单个对齐数整除)
2、整体对齐(整体大小能被对齐数整除,若不能不整除,则增加偏移来填充)

相同的成员变量,因为声明位置不同,导致占用内存空间不同,看下面代码

void test6()
{
//总对齐数min{编译器默认的对齐数=8 ,成员变量大小的最大值double=8 } = 8
struct node
{
//假设总体空间为all
double m;//8 double对齐数为8 ,此时all=8 [0:7]
int a;//4 int 对齐数为 4 all=12 [8:11]
char c;//1 char对齐数 1 all=13 [12]
char b;//1 char对齐数 1 all=14 [13]
};//16 开始整体对齐,要能被整体对齐数整除,也就是能被8整除,14不能被8整除,+2=16 即可,所以all=16

struct node1
{
	char c;		//1	 char对齐数  1         all=1
	int a;//4	       int对齐数  4  (char c 后空出三个字节,从第四个字节开始存放 int a)       all=8
	char b;			//1  char对齐数  1         all=9
	double m;//8    double对齐数为8  (char b 后空出7个字节,从第四个字节开始存放double m) ,此时all=24
};//24     24能被8整除,所以整体不需要偏移

cout << sizeof(node) << "---" << sizeof(node1) << endl;

}

单个成员变量对齐(也就是说,单个变量的起始地址能被单个对齐数整除)更加通俗的讲就是;double类型必须从被8整除的地址开始,int 必须从被4整除的地址开始,若起始地址不能被整除,则向后移动,直到能被整除,空出来的空间直接浪费,用空间换时间。

如果嵌套了结构体的情况,内层嵌套的结构体成员对齐到自己的最大对齐数的整数倍的地址,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

为什么要偏移
平台的原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取到某些特定类型的数据,否则抛出硬件异常。
性能的原因: 数据结构(尤其是栈)应该尽可能的在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SSM-Spring-AOP

目录 1 AOP实现步骤&#xff08;以前打印当前系统的时间为例&#xff09; 2 AOP工作流程 3 AOP核心概念 4 AOP配置管理 4-1 AOP切入点表达式 4-1-1 语法格式 4-1-2 通配符 4-2 AOP通知类型 五种通知类型 AOP通知获取数据 获取参数 获取返回值 获取异常 总结 5 …

【Linux】:线程安全 + 死锁问题

&#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&#x1f3fd;留言 &#x1f60d;收藏 &#x1f49e; &#x1f49e; &#x1f49e; 1. 线程安全和重入问题&…

数字电路期末复习

*前言&#xff1a;*写的东西不太全面&#xff0c;更多的是一个复习大纲&#xff0c;让你发现自己有哪些不懂的问题&#xff08;不懂的地方就去翻书或者问AI&#xff09;&#xff0c;如果能够解决提出的所有问题&#xff0c;那么过期末考一定不是问题。 这里写目录标题 数制和码…

python数据分析:使用pandas库读取和编辑Excel表

使用 Pandas&#xff0c;我们可以轻松地读取和写入Excel 文件&#xff0c;之前文章我们介绍了其他多种方法。 使用前确保已经安装pandas和 openpyxl库&#xff08;默认使用该库处理Excel文件&#xff09;。没有安装的可以使用pip命令安装&#xff1a; pip install pandas ope…

“AI人工智能软件开发公司:创新技术,引领未来

大家好&#xff01;今天我们来聊聊一个充满未来感的话题——AI人工智能软件开发公司。这个公司&#xff0c;用大白话说&#xff0c;就是专门研究和开发人工智能软件的地方&#xff0c;它们用最新的技术帮我们解决问题&#xff0c;让生活和工作变得更智能、更便捷。听起来是不是…

uniapp中使用ruoyiPlus中的加密使用(crypto-js)

package.json中添加 "crypto-js": "^4.2.0", "jsencrypt": "^3.3.2",但是vue2中使用 import CryptoJS from cryptojs; 这一步就会报错 参照 参照这里&#xff1a;vue2使用CryptoJS实现信息加解密 根目录下的js文档中新增一个AESwork.…

【SQL Server】教材数据库(1)

1 利用sql建立教材数据库&#xff0c;并定义以下基本表&#xff1a; 学生&#xff08;学号&#xff0c;年龄&#xff0c;性别&#xff0c;系名&#xff09; 教材&#xff08;编号&#xff0c;书名&#xff0c;出版社编号&#xff0c;价格&#xff09; 订购&#xff08;学号…

全国计算机设计大赛大数据主题赛(和鲸赛道)经验分享

全国计算机设计大赛大数据主题赛&#xff08;和鲸赛道&#xff09;经验分享 这是“和鲸杯”辽宁省普通高等学校本科大学生计算机设计竞赛启动会汇报—大数据主题赛的文档总结。想要参加2025年此比赛的可以借鉴。 一、关于我 人工智能专业 计赛相关奖项&#xff1a; 2022年计…

AI对接之JSON Output

AI的JSON Output 实际对接指南 前言 本系列AI的API对接均以 DeepSeek 为例&#xff0c;其他大模型的对接方式类似。 在现代软件开发中&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;作为一种轻量级的数据交换格式&#xff0c;因其简洁和易于人阅读的特…

Vue3实现PDF在线预览功能

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Vue篇专栏内容:Vue3现PDF在线预览功能 前言 在开发中&#xff0c;PDF预览和交互功能是一个常见的需求。无论是管理…

SpringBootWeb案例-1

文章目录 SpringBootWeb案例1. 准备工作1.1 需求&环境搭建1.1.1 需求说明1.1.2 环境搭建 1.2 开发规范 2. 部门管理2.1 查询部门2.1.1 原型和需求2.1.2 接口文档2.1.3 思路分析2.1.4 功能开发2.1.5 功能测试 2.2 前后端联调2.3 删除部门2.3.1 需求2.3.2 接口文档2.3.3 思路…

css实现垂直文本

效果 知识 writing-mode: <value>; 可选值 horizontal-tb: 默认值。文本从左到右&#xff08;或从右到左&#xff09;排列&#xff0c;然后从上到下。vertical-rl: 文本从上到下排列&#xff0c;然后从右到左。适用于垂直书写的方向&#xff0c;如日语和中文。vertica…

vim里搜索关键字

vim是linux文本编辑器的命令&#xff0c;再vi的基础上做了功能增强 使用方法如下 1. / 关键字, 回车即可, 按n键查找关键字下一个位置 2.? 关键字, 回车即可, 按n键查找关键字下一个位置 3.示例

Qt之QtConcurrent

简介 QtConcurrent是针对qt中多线程相关的高层封装&#xff0c;如QFuture 结构 Qtconcurrent命名空间中的run支持的有 其对应的functor下结构为 类关系 functor对应的类核心关系为 #mermaid-svg-KLxZquz9yRsiYvQL {font-family:"trebuchet ms",verdana,a…

鸿蒙应用开发搬砖经验之-ArkWeb加载页面的超简单示例

前言 系统环境&#xff1a;Mac mini M2 14.5 (23F79) 开发IDE&#xff1a;DevEco Studio 5.0.1 Release 示例 第一步&#xff1a;创建一个Empty Ability工程 第二步&#xff1a;先run一下&#xff0c;确定工程初步化正常&#xff0c;模拟器正常启动应用&#xff08;要先提…

大模型系列17-RAGFlow搭建本地知识库

大模型系列17-RAGFlow搭建本地知识库 安装ollama安装open-wehui安装并运行ragflowRAG&#xff08;检索、增强、生成&#xff09;RAG是什么RAG三过程RAG问答系统构建步骤向量库构建检索模块生成模块 RAG解决LLM的痛点 使用ragflow访问ragflow配置ollama模型添加Embedding模型添加…

SimForge HSF 案例分享|复杂仿真应用定制——UAVSim无人机仿真APP(技术篇)

导读 「神工坊」核心技术——「SimForge HSF高性能数值模拟引擎」支持工程计算应用的快速开发、自动并行&#xff0c;以及多域耦合、AI求解加速&#xff0c;目前已实现航发整机数值模拟等多个系统级高保真数值模拟应用落地&#xff0c;支持10亿阶、100w核心量级的高效求解。其低…

微电网到底是什么?和光伏有什么关系?

在现代能源体系中&#xff0c;微电网作为一种新型的电力系统结构&#xff0c;正逐渐受到广泛关注和应用。那么&#xff0c;微电网到底是什么&#xff1f;它与光伏又有怎样的关系呢&#xff1f;本文将对此进行详细解析。 微电网的基本概念 微电网&#xff08;Micro-Grid&#x…

印象笔记06——再谈谈更新

印象笔记06——再谈谈更新 [!CAUTION] 好吧&#xff0c;我承认在前五期的努力下&#xff0c;我还是用的obsidian多一些。印象笔记很大程度用来弄清单&#xff0c;但是扭头看了看自己的会员时间&#xff0c;不能浪费啊&#xff01;本期再谈谈印象笔记近期的一些更新&#xff0c;…

爱死机第四季(秘密关卡)4KHDR国语字幕

通过网盘分享的文件&#xff1a;love_death_robot 链接: https://pan.baidu.com/s/1bG3Xtdopenil2O_y93hY_g?pwd8kib 提取码: 8kib