关于内存对齐的全面详细解释

C/C++中结构体内存对齐(边界对齐),#pragma pack设置 一、首先,为什么要进行内存对齐,即在内存中为什么要这么存放数据呢??? 原因一:在内存中存放数据是为了给CPU使用,但是CPU从内存中读取数据并非是一个字节一个字节进行读取的,而是一块一块进行读取的,块的大小(具体和数据总线宽度等有关)称为内存读取粒度(memory granularity)。例如:CPU一次从内存读取8字节,而当一个int(4字节)存储在如下位置时,CPU如何获取该int值呢?... 阅读详情

一、内存对齐的原因
1、平台原因(移植原因):内存对齐其实不是操作系统内存架构范畴的问题,而是CPU架构方面的问题。不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。x86和x64系统支持自动内存对齐,IA-64系统则不能访问未对齐的内存地址。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

二、对齐规则
每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16...8192来改变这一系数,其中的n就是你要指定的“对齐系数”。关键字__declspec(align(n)),n=1,2,4,8,16...8192也能改变具体变量的对齐方式。

可以这样理解:
1、__declspec(align(n))和#pragma pack(n)是一对兄弟,前者规定了对齐系数的最小值,后者规定了对齐系数的最大值。
2、当两者同时出现时,前者拥有更高的优先级。即,当两者同时出现且值矛盾时,后者将不起作用。
3、当变量size大于等于#pragma pack(n)指定的n,而且__declspec(align(n))指定的数值n比对应类型长度小的时候,这个__declspec(align(n))指定将不起作用。
4、当#pragma pack(n)指定的值n大于等于所有数据成员size的时候,这个值n将不起作用。


简单数据成员对齐规则:
对齐系数 = max(__declspec(align(n))指定的n,min(自身size,#pragma pack(m)指定的m))。
结构型数据成员对齐规则:
对齐系数 = max(__declspec(align(n))指定的n,min(max(所有简单数据成员的size,包括嵌套),#pragma pack(m)指定的m))。
结构整体对齐规则:
对齐系数 = max(max(修饰该结构或修饰该结构成员的所有__declspec(align(n))指定的n,包括嵌套),min(max(所有简单数据成员的size,包括嵌套),#pragma pack(m)指定的m))。

上述规则看似很复杂,其实可总结为:
    对于成员对齐,第一个数据成员始终放在偏移为0的地方,在没有被__declspec(align(n))修饰时,以后每个数据成员的对齐,按照#pragma pack(n)指定的数值n和这个数据成员自身size中,比较小的那个进行;当被__declspec(align(n))修饰时,再使上述结果与__declspec(align(n))指定的n进行比较,然后按较大的那个进行。如果成员本身又是结构,则找到该结构中所有简单成员的size最大值,然后与#pragma pack(n)指定的数值n进行比较,取较小的那个;如果该结构成员本身被__declspec(align(n))修饰,再使上述结果与__declspec(align(n))指定的n进行比较,然后按较大的那个进行。
    对于结构整体的对齐,取结构中所有简单成员的size的最大值(如果有结构型成员,则将其展开,取其中的简单数据成员),然后与#pragma pack(n)指定的数值n进行比较,取较小者;如果结构或结构成员(包括嵌套)被__declspec(align(n))修饰,则取所有__declspec(align(n))(包括嵌套)指定的n的最大值,然后与上述得到的较小者进行比较,取其中的较大者。

三、试验
我们通过一系列例子的详细说明来证明这个规则吧!

我们首先确认在试验平台上的各个类型的size,以及默认对齐系数:
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(double) = 8

#pragma pack(show) = 8 (以警告的方式显示编译器当前的默认对齐系数)


例1:
1)成员数据对齐:
#pragma pack(1)
struct Str{
char a; /* 起始offset=0;存放位置区间[0] */
short b; /* min(2,1)=1 按1对齐;起始offset=1 1%1=0;存放位置区间[1,2] */
__declspec(align(8)) int c; /* max(8,min(4,1)) 按8对齐;起始offset=3 3%8=!0;直到增加为8 8%8=0;存放位置区间[8...11] */
double d; /* min(8,1)=1 按1对齐;起始offset=12 12%1=0;存放位置区间[12...19] */
char e; /* min(1,1)=1 按1对齐;起始offset=20 20%1=0;存放位置区间[20] */
};
成员总偏移量 = 21
2)整体对齐
整体对齐系数 = max(max(8),min(max(1,2,4,8,1),1)) = 8
21%8!=0;直到增加为24 24%8=0;所以整体的size = 24

例2:
1)成员数据对齐:
#pragma pack(16)
struct Str{
char a; /* 起始offset=0;存放位置区间[0] */
short b; /* min(2,16)=2 按2对齐;起始offset=1 1%2=!0;直到增加为2 2%2=0;存放位置区间[2,3] */
__declspec(align(2)) double c; /* max(2,min(8,16)) 按8对齐;起始offset=4 4%8=!0;直到增加为8 8%8=0;存放位置区间[8...15] */
int d; /* min(4,16)=4 按4对齐;起始offset=16 16%4=0;存放位置区间[16...19] */
};
成员总偏移量 = 20
2)整体对齐
整体对齐系数 = max(max(2),min(max(1,2,8,4),16)) = 8
20%8!=0;直到增加为24 24%8=0;所以整体的size = 24

例3:
1)成员数据对齐:
struct Str{
__declspec(align(16)) char a; /* 起始offset=0;存放位置区间[0] */
short b; /* min(2,8)=2 按2对齐;起始offset=1 1%2=!0;直到增加为2 2%2=0;存放位置区间[2,3] */
__declspec(align(2)) double c; /* max(2,min(8,8)) 按8对齐;起始offset=4 4%8=!0;直到增加为8 8%8=0;存放位置区间[8...15] */
int d; /* min(4,8)=4 按4对齐;起始offset=16 16%4=0;存放位置区间[16...19] */
};
成员总偏移量 = 20
2)整体对齐
整体对齐系数 = max(max(16,2),min(max(1,2,8,4),8)) = 16
20%16!=0;直到增加为32 32%16=0;所以整体的size = 32

例4:
1)成员数据对齐:
#pragma pack(1)
struct Str{
char a; /* 起始offset=0;存放位置区间[0] */
__declspec(align(2)) short b; /* max(2,min(2,1)) 按2对齐;起始offset=1 1%2=!0;直到增加为2 2%2=0;存放位置区间[2,3] */
};
struct Str总偏移量 = 4,按max(max(2),min(max(1,2),1))进行整体对齐后,其size为4。

struct Str2{
char a; /* 起始offset=0;存放位置区间[0] */
struct Str b; /* min(max(1,1,2),1) 按1对齐;起始offset=1 1%1=0;存放位置区间[1...4] */
};

struct Str2总偏移量 = 5
2)整体对齐
整体对齐系数 = max(max(2),min(max(1,1,2),1)) = 2
5%2!=0;直到增加为6 6%2=0;所以整体的size = 6

简单数据成员对齐规则:
对齐系数 = max(__declspec(align(n))指定的n,min(自身size,#pragma pack(m)指定的m))。
结构型数据成员对齐规则:
对齐系数 = max(__declspec(align(n))指定的n,min(max(所有简单数据成员的size,包括嵌套),#pragma pack(m)指定的m))。
结构整体对齐规则:
对齐系数 = max(max(修饰该结构或修饰该结构成员的所有__declspec(align(n))指定的n,包括嵌套),min(max(所有简单数据成员的size,包括嵌套),#pragma pack(m)指定的m))。

例5:
1)成员数据对齐:
struct Str{
char a; /* 起始offset=0;存放位置区间[0] */
__declspec(align(16)) short b; /* max(16,min(2,8)) 按16对齐;起始offset=1 1%16=!0;直到增加为16 16%16=0;存放位置区间[16,17] */
};
struct Str总偏移量 = 18,按max(max(16),min(max(1,2),8))进行整体对齐后,其size为32。

struct Str2{
int a; /* 起始offset=0;存放位置区间[0...3] */
__declspec(align(8)) struct Str b; /* max(8,min(max(1,2),8)) 按8对齐;起始offset=4 4%8=!0;直到增加为8 8%8=0;存放位置区间[8...39] */
double c; /* min(8,8)=8 按8对齐;起始offset=40 40%8=0;存放位置区间[40...47] */
char d; /* min(1,8)=1 按1对齐;起始offset=48 48%1=0;存放位置区间[48] */
};

struct Str2总偏移量 = 49
2)整体对齐
整体对齐系数 = max(max(8,16),min(max(4,1,2,8,1),1)) = 16
49%16!=0;直到增加为64 64%16=0;所以整体的size = 64

为什么要内存对齐? 为什么会有内存对齐? 平台原因: 不是所有的硬件平台都能访问任意内存地址上的数据,某些平台只能在一些地址处获取特定类型的数据,否则抛出硬件异常。为了使同一个程序可以在多平台运行,需要进行内存对齐。 硬件原因: ... 阅读详情

相关推荐

Linux内核模块开发实战指南(2025版)

2025年Linux内核模块开发迎来革命性突破!本文将从零开始手把手教你构建可动态加载的AI加速驱动模块,揭秘最新内核特性与开发技巧,更包含独家性能调优方案与跨架构移植秘籍。文末附赠价值百万的调试脚本,助你轻松突破开发瓶颈!

资深全栈架构师,乐于在 优快云 分享技术见解,与大家携手共进,共攀技术巅峰! 1809

为什么要进行内存对齐?本文也许可以帮到你

为什么存在内存对齐? 大部分的参考资料都是如是说的: 1. 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址 处取某些特定类型的数据,否则抛出硬件异常。 2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理 器需要作两次内存访问;而对齐的内存访问仅需要一次访问。 总体来说: 结构体的内存对齐是拿空间来换取时间的做法。 但是关于上面的说法,其实是很难理解的,但是相信上面也是大家搜到的最多的答

学无止境 742

鲁棒优化入门(6)—Matlab+Yalmip两阶段鲁棒优化通用编程指南(上)

Matlab+Yalmip两阶段鲁棒优化通用编程指南(上篇),内容包括: ①.拿到一个复杂的两阶段鲁棒优化问题的分析步骤和方法。 ②.采用Yalmip工具箱中的uncertain函数和鲁棒优化模块求解两阶段鲁棒优化的子问题。 ③.Yalmip工具箱中的鲁棒优化模块和常规的求解思路有什么异同。 ④.使用KKT条件求解两阶段鲁棒优化的子问题,并使用C&CG算法进行迭代求解。

配电网和matlab的博客 1万+

【内存】内存对齐 的原理

目录 内存对齐的原因 内存对齐的原理 内存对齐的原因 1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2.性能原因: 内存对齐最最底层的原因是内存的IO是以64bit为单位进行的,因此内存对齐为了高效的内存IO,大部分都是更为高效的高速缓存IO。 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。你i.

我的笔记本 2450

用Python玩转Milvus:从安装SDK到完成第一个向量搜索Demo

本文为Python开发者提供了一份详细的Milvus向量数据库实战指南。文章重点讲解了如何规避版本兼容性陷阱,正确部署Milvus服务端并安装匹配的Python SDK。通过一个电影推荐系统的完整案例,演示了从数据建模、集合创建、向量插入、索引构建到执行混合搜索的全流程,帮助开发者快速上手并完成第一个向量搜索Demo。

weixin_29239279的博客 192

Ollama内网离线部署大模型实战:从模型文件到私有化服务

本文详细介绍了如何在内网离线环境下,利用Ollama部署私有化大模型服务。内容涵盖从获取GGUF格式模型文件、手动安装Ollama、编写核心Modelfile配置文件,到创建运行模型、性能调优及安全加固的全流程实战指南,旨在帮助企业安全、可控地构建内部AI能力。

weixin_29209805的博客 215

LCD DRM驱动框架分析二

本文是基于rk3566 / rk3568平台从LCD代码层面上对LCD DRM框架进行分析。 一、uboot阶段 1、涉及的驱动文件 2、uboot代码流程分析 2.1)各probe函数的加载 2.1.1)各bind函数是在设备和驱动匹配时(uboot启动阶段)加载的。 2.1.2)各probe函数是在rockchip_display_probe中解析设备树时,通过uclass_get_device_by_xxx(uclass_get_device_by_ofnode/uclass_get.

qq_33782617的博客 5565

GD32_ADC采样+DMA多通道扫描传输

所使用的MCU 片上集成了 12 位逐次逼近式模数转换器模块(ADC),可以采样来自于 16 个外部通道和 2 个内部通道上的模拟信号。这 18 个 ADC 采样通道都支持多种运行模式,采样转换后,转换结果可以按照最低有效位对齐或最高有效位对齐的方式保存在相应的数据寄存器中。我们主要介绍其多通道扫描转换和DMA传输功能,在多个通道轮询采集ad数据,并使用DMA分别保存各个数据值,其能大大提高ADC的工作效率。以下为ADC 模块框图:

Yin_w的博客 8160

为什么要进行内存对齐?

关于内存对齐的博客,网上可以搜到很多,但是大多讲述的都是关于内存对齐的规则,所以本篇文章就不再继续介绍了,而至于为什么要进行内存对齐,如果细心的网友有进行过大量的搜索一定会发现,下面这段话是大家经常见到的: 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。 2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,对于访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

学无止境 2766

沁恒CH32V30X学习笔记02--GPIO的使用教程及2次封装驱动

刚复位后,GPIO 口运行在初始状态,这时大多数 IO 口都是运行在状态所有的 GPIO 口都可以被配置外部中断输入通道,但一个外部中断输入通道最多只能映射到一个GPIO 引脚上,且外部中断通道的序号必须和 GPIO 端口的位号一致,,两方都是一对一的关系。复用功能。

Car12 706

Modbus协议介绍及解析

Modbus协议介绍及解析 1.Modbus简介 Modbus是一种广泛应用于工业控制领域串行通信协议,以其开放性、高可靠性、高效简单性、免费等优点,成为了工业领域通信协议的业界标准,是工业现场电子设备之间常用的连接方式。Modbus按其格式可分为Modbus-RTU,Modbus-ASCII,Modbus-TCP,其中前两者适用于串行通信控制网络中,例如RS485,RS232等,而Modbus-TCP主要应用于基于以太网TCP/IP通信的控制网络中。通过此协议,控制器相互之间、或控制器和其它设备之间进行通

逍遥子的博客 1万+

关于内存对齐详细解释

什么是内存对齐? 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自的空间相加,这里涉及到内存对齐的问题。访问未对齐的内存,处理器需要访问两次(数据先读高位再读低位然后进行拼接),而访问对齐的内存,只需要一次。为了提高效率,所以进行内存对齐。windows的默认对齐数是8,linux中默认对齐数为4. 为什么会产生内存对齐的原因? 1.平台原因: 某些...

suoyudong的博客 1145

【机器学习与数据挖掘实战 | 商务】案例03:基于k近邻算法的非侵入式电力负荷监测与分解的电力分析

本案例结合非侵入式电力负荷监测与分解的案例,重点介绍了在数据可视化的辅助下k近邻算法的应用。首先利用数据可视化寻找数据的特征,构建特征集合。然后构建k近邻模型,利用构建的特征集合训练模型,接着利用该模型对单一设备所属类别进行判定,最后计算实时用电量。

Morse_Chen的博客 2303

KaihongOS落地实战:架构、开发、编译与排查全解析

操作系统是连接硬件与应用生态的桥梁,多内核抽象与分布式协同正成为新型系统设计的核心。KaihongOS 通过内核抽象层与分布式软总线,将设备能力资源化,让应用无需感知物理拓扑即可跨端调用,真正实现一次开发、多端部署。其构建系统与工具链支撑从源码到镜像的完整流程,设备烧录与日志调试则保障交付效率。实际落地中,处理好设备发现、时钟同步与权限管控等隐性坑,结合UI渲染与内存的性能调优,是团队从Demo走向规模交付的关键。本文以工程视角拆解KaihongOS的架构原理与实战经验,为多设备场景下的开发与适配提供参考。

weixin_34269583的博客 357

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

内存对齐详细解释

内存对齐详细解释 如果结构体存储下标从0開始的 先是依照#pragma pack(8)參数依次和数据成员比較:依照成员下标是比較结果中小者的倍数; 最后再依照#pragma pack(8)參数与结构体成员占空间最大者比較,结构体总体的长度是比較结果中小者的倍数;   1、分析说明: 字节对齐(#pragma pack(2)) 输出结果:sizeof(structtest_t)...

weixin_33756418的博客 124

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

posix_memalign详细解释(转)——自定义对齐大小的内存分配函数

转载:http://hi.baidu.com/freelonely/blog/item/340341077c4d287302088189.html 预对齐内存的分配 在大多数情况下,编译器和C库透明地帮你处理对齐问题。POSIX 标明了通过malloc( ),calloc( ), 和realloc( )返回的地址对于任何的C类型来说都是对齐的。在Linux中,这些函数返回的地址在32位系...

weixin_30485799的博客 251

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

内存对齐、内存对齐规则解释、内存对齐原理

一、内存对齐的原因 我们都知道计算机是以字节(Byte)为单位划分的,理论上来说CPU是可以访问任一编号的字节数据的,我们又知道CPU的寻址其实是通过地址总线来访问内存的,CPU又分为32位和64位,在32位的CPU一次可以处理4个字节(Byte)的数据,那么CPU实际寻址的步长就是4个字节,也就是只对编号是4的倍数的内存地址进行寻址。同理64位的CPU的寻址步长是8字节,只对编号是8的倍数的内存...

草帽~小子^的博客 7393

什么是内存对齐

内存对齐

qq_42376419的博客 1535

结构体内存对齐

本文简要介绍了c/c++中内存对齐,总体来说和边界对齐类似,并对其使用的原因做出了简单的介绍

黎鹤舞828的博客 1731

什么是内存对齐?为什么要内存对齐?

要了解为什么要内存对齐,首先我们要了解什么是内存对齐 什么是内存对齐 关于什么是内存对齐,我们先来看几个例子 typedef struct { int a; double b; short c; }A; typedef struct { int a; short b; double c; }B; 分别对他们求大小,sizeof(A)...

zw_ss 4万+

[C++] 内存对齐的目的和原则是什么?如何调整内存对齐的值

为什么需要内存对齐? 内存对齐(memory alignment).为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。也就是说“内存对齐”应该是编译器的管辖范围,非常依赖平台. 全局关闭内存对齐 先来看下面的结构体: struct test{ int a; int b; char c; }A; 1 添加预处理指令 #pragma pack(1) #paragma pac

小x的博客 4229

linux内存对齐

一,内存地址对齐的概念    计算机内存中排列、访问数据的一种方式,包含基本数据对齐和结构体数据对齐。    32位系统中,数据总线宽度为32,每次能够读取4字节数据。地址总线为32,最大寻址空间为4GB。但是由于最低位A[0]~A[1]是不用于寻址的,因此只能访问4的倍数的地址空间,但是寻址空间还是2^30*字长=4GB。   因此内存中除了结构体中成员变量之外的基本类型的开始

逐波与逆流 2784

C 内存对齐

C 内存对齐 对于程序员来说,最烦恼最耗时的工作莫过于与内存打交道,但是内存至关重要,不得不对其保持最大的警惕。 为什么需要内存对齐? 平台原因:不是所有的一欧诺个见平台都能访问任意地址上的任意数据的;某些硬件平台如果访问未对齐的地址,则会报出对齐错误,有些专业的处理器通常不支持访问未对齐地址。 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界对其。原因在于,为了访问未对齐的内存,...

hao555sky 262
上一篇: 大端,小端
下一篇: DC保存至BMP图像
desow
博客等级 码龄17年 36粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值