一、内存对齐的原因

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

这样做可以实现最快速的方式寻址且不会遗漏一个字节,也不会重复寻址。

那么对于程序而言,一个变量的数据存储范围是在一个寻址步长范围内的话,这样一次寻址就可以读取到变量的值,如果是超出了步长范围内的数据存储,就需要读取两次寻址再进行数据的拼接,效率明显降低了。例如一个double类型的数据在内存中占据8个字节,如果地址是8,那么好办,一次寻址就可以了,如果是20呢,那就需要进行两次寻址了。这样就产生了数据对齐的规则,也就是将数据尽量的存储在一个步长内,避免跨步长的存储,这就是内存对齐。在32位编译环境下默认4字节对齐,在64位编译环境下默认8字节对齐。

查看自己电脑是多少位操作系统
终端下输入:uname -a 回车
x86_64 表示系统为64位
i686 表示系统32位的

二、对齐规则
1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的偏移为 #pragma pack 指定的数值和这个数据成员自身长度中较小那个的整数倍。
2:数据成员为结构体:如果结构体的数据成员还为结构体,则该数据成员的“自身长度”为其内部最大元素的大小。(struct a 里存有 struct b,b 里有char,int,double等元素,那 b “自身长度”为 8)
3:结构体的整体对齐规则:在数据成员按照 #1 完成各自对齐之后,结构体本身也要进行对齐。对齐会将结构体的大小增加为 #pragma pack 指定的数值和结构体最大数据成员长度中较小那个的整数倍。

(看不懂没关系,因为我也没看懂,也是打印之后才明白)

三、实例

typedef struct test1 {char a;//1int b;//4字节double c;//8char d[11];//11
}Test1;//数据成员int main(int argc, const char * argv[]) {Test1 t1;//xcode默认对齐系数8,即#pragma pack(8)//char a,     1<8按1对齐,offset=0            [0]//int b,      4<8按4对齐,char a占到[0],int b应该从地址1开始排, 地址1不是对齐数4的倍数,所以int b的首地址是从4的最小倍数开始,所以offset=4,       [4...7];//double c,   8=8按8对齐,int b已经占到[4...7],double c从地址8开始排,地址8是对齐数8的倍数,所以double c的首地址是从8的最小倍数开始,offse=8             [8...15]//char d[11], 1<8按1对齐,double c已经占到[8...15], char d[11]从地址16开始,地址16是对齐数1的倍数,所以char d的,offset=16,          存储位置[16...26]//最后为27位,又因为27不是内部最大成员中double 8位字节的倍数,所以补齐为32)printf(" %lu\n %p\n %p\n %p\n %p\n", sizeof(t1), &t1.a, &t1.b, &t1.c, &t1.d);return 0;
}

结果:

 320x7ffeefbff5680x7ffeefbff56c0x7ffeefbff5700x7ffeefbff578

以首地址0x7ffeefbff568为offset=0,
0x68=104,
0x6c=108,
0x70=112,
0x78=120,
0x7ffeefbff56c相对于0x7ffeefbff568便宜了4,
0x7ffeefbff570相对于0x7ffeefbff568便宜了8,
0x7ffeefbff578相对于0x7ffeefbff568偏移了16,符合规律
上面int b正好偏移4,double c正好偏移8,比较凑巧,如果char a[5]呢,使地址正好措开,此时int b应该是[8…13],double c应该是[16…23], char d[11]应该是[24…34],34不是最大double c的整数倍,补齐到最小倍数40,所以结构体的大小应该是40.

 400x7ffeefbff5600x7ffeefbff5680x7ffeefbff5700x7ffeefbff578
Program ended with exit code: 0

在结构体struct Test1中添加一个结构体Test2,看下结果:

typedef struct test2 {char a[13];//1      [0...13]double b;//8        [16...23]int c[11];//4       [24...67]float d;//4         [68...71]
}Test2;typedef struct test1 {char a[5];//1       [0...4]int b;//4           [8...11]double c;//8        [16...23]char d[11];//11     [24...34]Test2 t2;//         [40...111] Test2的'自身长度'为double b=8,所以从8的最小倍数开始,即40
}Test1;//数据成员
//此时:
//  char a[13];//1      [40...52]
//  double b;//8        [56...63]
//  int c[11];//4       [64...107]
//  float d;//4         [107...111]int main(int argc, const char * argv[]) {Test1 t1;Test2 t2;printf(" %lu\n", sizeof(t2));printf(" %lu\n", sizeof(t1));return 0;
}

结果:

 72112
Program ended with exit code: 0

把Test2中的double b注销了,看下结果:

typedef struct test2 {char a[13];//1      [0...13]//double b;//8        [16...23]int c[11];//4       [16...59]float d;//4         [60...63]
}Test2;typedef struct test1 {char a[5];//1       [0...4]int b;//4           [8...11]double c;//8        [16...23]char d[11];//11     [24...34]Test2 t2;//64       [36...99] 此时Test2的'自身长度'为int c=4,所以从4的最小倍数开始,即36开始,又因为100不是double c的倍数,补齐到最小倍数104
}Test1;//数据成员int main(int argc, const char * argv[]) {Test1 t1;Test2 t2;printf(" %lu\n", sizeof(t2));printf(" %lu\n", sizeof(t1));return 0;
}
 64104
Program ended with exit code: 0

四、更改默认对齐系数

#pragma pack(2)//1、2、4、8、16,以2为例typedef struct test2 {char a[13];//1      [0...13]//double b;//8        [16...23]int c[11];//4    2<4   [14...57]从2的最小倍数开始,即14float d;//4         [58...61]
}Test2;
int main(int argc, const char * argv[]) {Test2 t2;printf(" %lu\n", sizeof(t2));return 0;
}

结果:

 62
Program ended with exit code: 0

参考:

https://www.jianshu.com/p/f01fe1ef892d

内存对齐、内存对齐规则解释、内存对齐原理相关推荐

  1. C字节对齐与C++类对象内存布局

    一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问, ...

  2. 语言结构体在内存的分布_结构体内存对齐,这篇文章给你彻底搞会!(干货收藏)...

    脚本之家 你与百万开发者在一起 公众号:C语言编程 作者:薛定谔的coding猫 一.内存对齐的原因  1.平台原因(移植原因):一些资料上是这样说的,"不是所有的硬件平台都能访问任意地址上 ...

  3. 【高性能计算】为什么内存需要8字节或16字节对齐

    "8字节对齐"的对象存储在以8为倍数的内存地址中. 许多CPU只会从对齐的位置加载一些数据类型:在诸多CPU上,这样的访问速度更快.使用内存对齐还有其他几个可能的原因--如果没有看 ...

  4. C语言 | 内存对齐02 - 为什么会有内存对齐?它解决了什么问题

    文章目录 一.前言 二.内存对齐为4个字节的好处 三.内存对齐的目的是以空间换取速度 3.1.内存对齐为4的例子 3.2.内存没有使用内存对齐的例子 四.掌握内存对齐的必要性 一.前言 内存对齐的目的 ...

  5. Objective-C 内存管理之ARC规则

    基本概念 ARC为自动引用计数,引用计数式内存管理的本质并没有改变,ARC只是自动处理"引用计数"的相关部分. 在编译上,可以设置ARC有效或无效.默认工程中ARC有效,若设置无效 ...

  6. java虚拟机之一内存运行时数据区域解释

    Java虚拟机管理的内存运行时数据区域解释 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启 ...

  7. 内存池、自由空间、堆内存 等名称解释(不间断更新。。。)

    简单说说几个名词解释:(c++ primer 第五版) 1. 内存池.自由空间.堆内存 其实是同一种概念的不同叫法. 编译器分配的内存,一般在全局存储区,要么在栈内存等. 堆内存,是程序员自己分配的内 ...

  8. 金士顿服务器内存条型号解读,金士顿骇内存新版型号编码规则是什么?

    金士顿骇内存新版型号编码规则是什么? 现在很多人都在用金士顿骇内存和存储设备,为了让大家更加了解金士顿骇内存新版型号编码规则本文盘点一下内存.骇客神条.编码规则的小知识. 注:编码规则,对普通电脑使用 ...

  9. 小科普 | BIOS设置选项详细解释②——内存篇

    原标题:小科普 | BIOS设置选项详细解释②--内存篇 Load XMP Setting:加载XMP预设.内存出厂后会进行测试,找到一些电压.时序.频率之间稳定运行的参数,保存在内存XMP文件当中, ...

  10. 整数边界对齐方式_嵌入式基础——字节对齐

    字节对齐 一.内存访问对齐规则 从高级语言的视角看,内存访问是是字节为单位的. 但是从CPU角度看,内存访问粒度与指令有关,比如1字节访问,2字节访问,4字节访问,8字节访问等. 如果在编程过程中不注 ...

最新文章

  1. 数据库访问类(使用存储过程的)
  2. 驱动学习模块最简单示例
  3. poi jxl 生成EXCEL 报表
  4. HDU 2003 求绝对值
  5. 5.jQueryAjax
  6. java面向对象super_【JavaSE】面向对象之super、final
  7. linux make java版本,告诉make是否在Windows或Linux上运行
  8. python3打印不换行
  9. OpenCV模板匹配函数:matchTemplate()介绍
  10. win11怎么回退原系统 Windows11回退的步骤方法
  11. python pip 安装 win10 解决anacoda代理错误 ProxyError: Conda cannot proxy configuration
  12. 手机论文查重软件哪个靠谱?
  13. Pytorch Note19 优化算法5 Adadelta算法
  14. JS实现网页截图的三种方案
  15. 揭秘3D游戏模型贴图师
  16. Js 实现十六进制颜色值和RGB颜色值转换整理
  17. CSS预处理器语言:Sass、LESS、Stylus
  18. 808 Lab虚拟插件:Sample Science 808 Lab for Mac
  19. 基金从业考试如何备考?
  20. Web缓存中毒(web cache poisoning)学习笔记

热门文章

  1. 机器人学导论——笔记(1)
  2. Coursera | Introduction to Data Analytics(IBM) | Final Assignment
  3. 超详细的QSS样式表入门Demo
  4. 自己编写的C语言实时时钟代码
  5. Scala - Redis hgetAll 优化 by hscan
  6. 数学分析-基本积分表
  7. WEB密码安全输入控件
  8. 个人--2015 关于管理的书
  9. Mapped Statements collection already contains value for com.wen.mapper.ProjectMapper.xxx
  10. 双人游戏根据胜负关系匹配