C/C++中内存对齐问题

C/C++中内存对齐问题的一些理解 内存管理是C/C++编程非常重要的一部分内容,熟悉C/C++中一些常见数据结构和数据类型的内存分布情况,可以很大程度上降低了coding过程中内存泄漏和越界等比较严重的内存问题,下面主要讨论一下结构体(类中同样存在内存对齐,内存对齐会复杂一些,涉及到虚表等问题,后面介绍类的时候会提到)中的内存对齐问题。 如有侵权,请联系删除,如有错误,欢迎大家指正,谢谢 内存对齐指令 一般来说,内存对齐过程对c... 阅读详情

最近做了些牛客上的笔试题,果然发现很多不足之处,感觉大一的C++白学了,心累QAQ。

问题:

有四个类A B C定义如下, 请确定sizeof(A),sizeof(B) ,sizeof(C),sizeof(D)的大小顺序.

class A
{
    int x;
    int y;
};
class B :public A
{
    int x;
    char y;
};
class C
{
    C()
    {
    }
    virtual ~C()
    {

    }
    int x;
    short y;
};
class D
{
    int x;
    char y;
};

解析:

首先补充一点内存对齐的规则。

结构体或类的的内存分配规则:

从结构体或类的首地址开始向后依次为每个成员寻找第一个满足条件的首地址x,条件为x%N==0(N为成员的自身对齐值),并且结构的长度必须为每个成员自身对齐值最大的那个值的最小整数倍,不够的话就补空字节。
结构体或类的自身对齐值为所有成员中自身对齐值最大的那个。

在32位机+32系统下
A的大小为8,很容易得出的。
B继承自A,B的起始存储大小是从第8字节开始的,B::x占4个字节,B::y从第12个字节开始,B::y占一个字节,计算得B的大小应该是13,但是根据类的对齐规则(结构体或类的自身对齐值是其成员自身对齐值最大的那个值,本题B的成员自身对齐值最大的为4(int)),所以B::y后面还要补充三个字节,B的大小为16。
C的大小为12。类C中有虚函数,包含虚函数指针,虚函数占4个字节。本来计算得大小为10,但是C的自身对齐值为4,如果C的地址空从0x0000开始,那么此时0x000A%4(对齐值)!=0,所以要在C::y后面再补充2个字节,大小变成12,0x000C%4==0。
D的大小为,和上面的计算方法差不多。

下面就正式开始介绍内存对齐了。尤其感谢这篇博客,写的很详尽。下面的内容很多都是参考这篇博客的,O(∩_∩)O!

http://blog.youkuaiyun.com/hbuxiaofei/article/details/9491953

内存对齐

概念:

对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,它就称为自然对齐。比如在32位cpu下,一个整型变量的地址为0x00000004,那它就是自然对齐(起始地址能被4整除)。

需要字节对齐的原因:

需要字节对齐的根本原因在于cpu访问数据的效率问题。假设上面整型的变量地址不是自然对齐,比如为0x00000002,则cpu如果取它的值的话需要访问两次内存。第一次取从0x00000002~0x00000003的一个short,第二次取从0x00000004~0x00000005的一个short然后组合得到所要的数据。如果变量在0x00000003地址上,则需要访问3次,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量地址在自然对齐位置上,只需要一次就能取得数据。除此之外,合理的利用字节对齐能有效的节省存储空间。

正确处理字节对齐

对于标准数据类型,它的地址只要是它的长度的整数倍就行了,而非标准数据类型按下面的原则对齐:

  数组:按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。
  联合:按其包含的长度最大的数据类型对齐。
  结构体:结构体中每个数据类型都要对齐。
比如有如下一个结构体:

struct stu{
char sex;
int length;
char name[10];
};
struct stu my_stu;

  由于在x86下,GCC默认按4字节对齐,它会在sex后面跟name后面分别填充三个和两个字节使length和整个结构体对齐。于是我们sizeof(my_stu)会得到长度为20,而不是15。

什么时候需要设置对齐

在设计不同CPU下的通信协议时,或者编写硬件驱动程序时寄存器的结构这两个地方都需要按一字节对齐。即使看起来本来就自然对齐的也要使其对齐,以免不同的编译器生成的代码不一样。

更改C编译器的缺省字节对齐方式

在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:

· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。

#pragma pack(1)
class D
{
    int x;
    char y;
};

此时sizeof(D)等于5。

字节对齐对程序的影响:
struct A
{
        int a;
        char b;
        short c;
};
struct B
{
        char b;
        int a;
        short c;
};

sizeof(struct A)=8;
sizeof(struct B)=12;

之所以出现上面的结果是因为编译器要对数据成员在空间上进行对齐。上面是按照编译器的默认设置进行对齐的结果。

下面就是最最重要的内容了。
我们想知道编译器是按什么规则对齐的。

四个重要的基本概念:

1.数据类型自身的对齐值:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。

2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。

3.指定对齐值:#pragma pack (value)时的指定对齐值value。

4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。

有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的”存放起始地址%N=0”.而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。
例子分析:
分析例子B;
struct B
{
char b;
int a;
short c;
};
假设B从地址空间0x0000开始排放。该例子中没有定义指定对齐值,在笔者环境下,该值默认为4。第一个成员变量b的自身对齐值是1,比指定或者默认指定对齐值4小,所以其有效对齐值为1,所以其存放地址0x0000符合0x0000%1=0.第二个成员变量a,其自身对齐值为4,所以有效对齐值也为4,所以只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自身对齐值为2,所以有效对齐值也是2,可以存放在0x0008到0x0009这两个字节空间中,符合0x0008%2=0。所以从0x0000到0x0009存放的都是B内容。再看数据结构B的自身对齐值为其变量中最大对齐值(这里是b)所以就是4,所以结构体的有效对齐值也是4。根据结构体圆整的要求,0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B共有12个字节,sizeof(structB)=12;其实如果就这一个就来说它已将满足字节对齐了,因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.其实诸如:对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,这些已有类型的自身对齐值也是基于数组考虑的,只是因为这些类型的长度已知了,所以他们的自身对齐值也就已知了。

结构体A,结构体B

从零构建:Esp32+Esp-IDF驱动ST7789屏幕并集成LVGL图形库 本文详细介绍了如何从零开始使用Esp32和Esp-IDF驱动ST7789屏幕并集成LVGL图形库。内容涵盖环境准备、SPI驱动配置、屏幕初始化、LVGL图形库集成及常见问题排查,帮助开发者快速实现高效稳定的显示解决方案。 阅读详情

相关推荐

一文读懂,WMS仓库管理系统模块功能

对于仓库管理人员来说,仓储管理是一件需要十分负责、又精细化的工作。

深蓝易网的博客 5218

关于内存对齐的理解

复合数据类型,如union,struct,class的对齐方式为成员中对齐方式最大的成员的对齐方式。 顺便提一下CPU对界问题,32的C++采用8位对界来提高运行速度,所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的,使用#pragma pack(x)宏可以改变编译器的对界方式,默认是8。C++固有类型的对界取编译器对界方式与自身大小中较小的一个。例如,指定编译器按2对界

344

Eigen 直线拟合/曲线拟合/圆拟合/椭圆拟合

使用Eigen库进行直线拟合是数据分析和科学计算中的常见任务,主要通过最小二乘法实现。该代码演示了二维空间中的直线拟合,输出斜率和截距。

深之JohnChen的专栏 1594

【C/C++】详解内存对齐问题,C语言内存对齐整理

本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型、内存对齐问题等等。

艾莉丝努力练剑的博客,感谢大家一直以来的对艾莉丝的支持和鼓励,uu们如果对C/C++方向感兴趣的话,可以通过艾莉丝主页的微信名片加艾莉丝的好友,和努力练剑的艾莉丝一起加油! 1508

【Vite+Vue3+TS】基于Vite+Vue3+TypeScript+ESLint+Prettier+Stylelint搭建项目(亲测超详细)

结合了很多项目和文章,总结一篇项目构建的笔记。 温馨提示:文章末尾记录了我在搭建项目过程中,遇到的一些问题和解决办法 ~

aDiaoYa_的博客 4231

爬取国家统计局最近10年年度数据

一、编码流程 1.目标网址:https://data.stats.gov.cn/easyquery.htm?cn=C01 2.编码思路: (1) 解析左侧指标树,实现4级标签定位 (难点:层层嵌套,下一级指标的xpath路径以上一级指标为基础;不是所有二级指标都含有三和四级指标,需要进行判断) (2) 使用selenium webdriver 点选指标,加载出右侧表格数据 (难点:当指标无法在全局页面显示时,需向下拖动滚动条) (3) 解析右侧数据,实现数据存储 3.使用模块: (1) selenium:解

weixin_39645690的博客 4557

C/C++编程笔记:C语言对齐问题【结构体、栈内存以及位域对齐】

引言 考虑下面的结构体定义: 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4。 现在,我们编写一个简单的程序: 运行后输出: 为什么会这样?这就是字节对齐导致的问题。 本文在参考诸多资料的基础上,详细介绍常见的字节对齐问题。因成文较早,资料来源大多已不可考,敬请谅解。 一,什么是字节对齐 现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访

致力于C语言C++知识分享! 835

YOLO26改进策略【YOLO和Mamba】| 替换骨干 Mamba-YOLO26-T !!! 最新的发文热点

模块是模型中的一个重要组成部分,其主要作用是在模型的初始阶段对输入图像进行处理,方便后续的特征提取和目标检测。以下是对。

Limiiiing的博客 900

C/C++ 中内存对齐问题

我们通过几个例子来全面搞懂c/c++中的内存对齐问题。来看看下面的结构体大小分别是多大?(假设均在32位机器上)     struct A { char a; char b; char c; };     这个相信大家都知道,由于变量都是char类型,对齐值为1,所以结构体大小为3。 struct B { int a; char b; short c; };     对齐值

常敲代码手不抖 834

车载诊断架构 --- 车载ECU开发中DTC数量与芯片存储能力的关系及应对策略

本文探讨了汽车电子系统中ECU存储DTC故障码的容量问题及解决方案。作者作为汽车电子工程师,针对台架测试中遇到的DTC存储超限案例展开分析,指出随着汽车智能化发展,ECU需处理的DTC数量激增与芯片存储能力有限的矛盾。文章详细介绍了DTC的存储需求、ECU支持数量与芯片容量的关系,并提出应对策略,通过实际案例验证了方案的可行性。最后强调在ECU开发中需合理分配存储资源,确保关键故障信息不丢失。

Soly_kun的博客 87

【CAD二次开发】炸开所有的嵌套块

代码】【CAD二次开发】炸开所有的嵌套块。

1513

C/C++内存对齐问题探讨

C/C++内存对齐       最近几天开始翻阅《深度探索C++对象模型》,遇到了一些疑惑,也解决了一些,做笔记记录一下,跟我一样迷惑过的同学我们可以一块学习一下。这篇笔记说说内存对齐问题。 一、关于内存对齐     现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,

zhckf的专栏 499

在jetson上对fastdeploy进行源码编译(完整版)

在大多数Linux发行版中,你可以使用包管理器安装Python开发包。根据jetpack的版本选择对应的推理库版本。在~/.bashrc中写入这三行。

如果想成为中心,那么就到中心去吧。 678

C/C++中的内存对齐问题

内存对齐的三条规则 数据成员对齐规则,结构体(struct)(或联合(union))的数据成员,第一个数据成员存放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员(只要该成员有子成员,比如数组、结构体等)大小的整数倍开始(如:int 在 64bit 目标平台下占用 4Byte,则要从4的整数倍地址开始存储) 结构体作为成员,如果一个结构体里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储 结构体的总大小,即sizeof的结果,必须是其内部最大成

DayDayUp 845

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【我的C语言学习进阶之旅】关于C/C++内存对齐读取文件产生的问题以及解决方法

一、问题描述 今天在使用OpenGL ES 加载一个 TGA 图片文件的时候,出现了加载失败的问题。 关于什么是TGA文件以及如何打开TGA文件? 可以参考我的博客:【我的OpenGL学习进阶之旅】什么是TGA文件以及如何打开TGA文件? 如下图所示,没有texture加载进来,黑黢黢的页面。 查看日志打印,发现加载tga图片失败,如下所示: 2021-11-25 15:42:31.690 6385-6548/com.oyp.openglesdemo I/NDK_JNI_LOG_TAG: [GLUt

字节卷动 1384

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C/C++中关于结构体中内存对齐的问题

vs中的默认对齐数是8,第二个成员变量是int i,它的大小是4字节,而默认值为8,所以对于i来说对齐数是4,4的整数倍位置中,地址4是满足的,所以第二个成员变量应从4开始;而对齐的内存访问仅需要一次访问。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

2301_81791624的博客 723

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C/C++内存对齐问题

为何需要内存对齐? 尽管内存以字节为单位,但是大部分处理器并不是按照字节块来存取内存的。它一般会以双字节、四字节、8字节、16字节甚至32字节为单位来存取内存,这些存储单位被称为内存存取粒度。 从Cache角度看 从上图可以看出,一个cache line保存了2^b个字节。如果没有内存对齐规则,数据可以随意存放,那么可能导致一个变量被分隔在两个cache line中,这样处理器就需要读取两行cache line然后再将其合并成一个变量。 从物理内存角度看 从上图中可以看出内存模块由8个8Mx8的DRA

qq_38600065的博客 479

C/C++中的结构体对齐问题(内存对齐)

C/C++中的结构体对齐问题(内存对齐) 分类: c++ 2009-10-18 17:02 22人阅读 评论(0) 收藏 举报 由于程序运行时占用的内存过大,所以想办法给程序瘦身。 在调试中发现结构体占用的size竟然和预想的不一样,原来…… 看看下面讲的吧,肯定会不枉此看哦! 1,比如: struct{ short a1; short a2; sh

小菜鸟的专栏 956

C/C++ 中结构体的内存对齐问题?

默认对齐:由系统平台决定(Windows 常为 8,Linux 常为 4)。对齐规则:成员对齐 → 结构体对齐 → 总体大小补齐。C++11alignof获取对齐数,alignas指定对齐方式,但不能小于自然对齐。强制单字节对齐:需使用或。位域:可精确控制二进制存储,但依赖编译器实现。😀 关注 @公众号 程序员陈子青,获取更多 C++ 技术支持。

陈子青的博客 712

位域 内存 字节序_C/C++编程笔记:C语言对齐问题【结构体、栈内存以及位域对齐】...

引言考虑下面的结构体定义:假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4。现在,我们编写一个简单的程序:运行后输出:为什么会这样?这就是字节对齐导致的问题。本文在参考诸多资料的基础上,详细介绍常见的字节对齐问题。因成文较早,资料来源大多已不可考,敬请谅解。一,什么是字节对齐现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访...

weixin_39788703的博客 363

C/C++中关于结构体内存对齐问题

结构体内存对齐规则 第一个成员在与结构体变量偏移量为0的地址处。 其他成员要对齐到某个数字(对齐数)的整数倍的地址处。 编译器默认的一个对齐数与该成员大小的较小值。(vs中默认8,Linux中默认4) 3.如果设置了内存对齐为 i 字节,类中最大成员对齐字节数为j,那么整体对齐字节n = min(i, j) 。 结构体总体大小为最大对齐数(每个成员变量都有一个对齐数)的总数倍。 如果嵌套了结构体...

YIUECHEN的博客 498
上一篇: HDU 5012 Dice
下一篇: poj3083Children of the Candy Corn
_IanXiao
博客等级 码龄12年 84粉丝 241原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值