看的懂的字节对齐分析
#写在开头, 编译器的对齐值为8byte
如题, 首先说一下为什么需要字节对齐, 这个似乎有些浪费空间, 那就先上一下比较书面的解释:
1. 平台要求, 某些CPU只能访问地址为偶数的内存地址, 这个时候你把数据放在奇数地址, 就会报错
2. 性能要求, 这个跟寄存器有关系, 有些数据不对齐的话需要使用寄存器的次数会增多
说点通俗的, 就像一本书, 每页都有字, 但是不一定要写满; 写太满了, 没有章法, 看不了.
下面, 先说明三个概念:
1. 自身对齐值: 比如, short为2byte, double为8byte
2. 指定对齐值: 编译器自己决定的; 或者程序员自己决定的
1 #pragma pack (n) 2 *** 3 *** 4 #pragma pack ()
那么2, 3行内部的数据指定对齐值便是n
3. 有效对齐值: 上面两个值的最小值
对齐的规则呢:
1. 数据本身存储的地址应该是, 数据本身有效对齐值的整数倍
2. 对于结构体而言, 由于1这条规则, 以及有结构体数组的存在, 所以结构体本身的有效对齐值为内部 数据有效对齐值的最大值.
这么说还是比较抽象, 我们上点例子
1 struct A { 2 char a; 3 int b; 4 };
首先a的自身对齐值为1, 制定对齐值为8, 那么有效对齐值为min{1, 8} = 1
0x0 | 0x1 | 0x2 | 0x3 |
a |
接下来, 需要把b放进去, 他的地址应该时自身有效对齐为min{4, 8} = 4, 所以0x1, 0x2, 0x3都存不了,得从0x4开始存储
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 |
a | b | b | b | b |
如上, 很简单对吧, 下面讲一下规则2, 给结构体A加个char c
1 struct A { 2 char a; 3 int b; 4 char c; 5 };
那么有趣的事情就会发生, a的有效对齐值为1, b的为4, c的为1, 那么A的就是4, 所以c的后面3个单元会被占用, 想一想, 如果不这样补齐的话, 你想想对于结构体数组的第二个元素的b他的地址就不是4的整数倍了.
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB |
a | b | b | b | b | c |
所以, 究其根本, 所有的一切都是为了满足第1条规则.
那么再来如果把b换成double类型的呢?
1 struct A { 2 char a; 3 double b; 4 char c; 5 };
那么a的有效对齐值为1, b为8, c为1, A为8, 那么整体应该占24byte
0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | 0x7 | 0x8 | 0x9 | 0xA | 0xB | 0xC | 0xD | 0xE | 0xF | 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17 |
a | b | b | b | b | b | b | b | b | c |
光说不练假把式, 我们上几道题目
1 #pragma pack (4) 2 struct S1 { 3 char a; 4 double b; 5 }; 6 7 struct S2 { 8 char a; 9 S1 s; 10 char b; 11 char c; 12 }; 13 14 struct S3 { 15 int a; 16 char b[10]; 17 }; 18 #pragma pack ()
注意指定对齐值被改为了4, 拿自己的IDE试试吧!
有问题, 请联系760521757@qq.com
原文地址:https://www.cnblogs.com/zhangzixu/p/11588300.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android 实现IOS选择拍照相册底部弹出的实例
- ubuntu 20.04上搭建LNMP环境的方法步骤
- Android实现界面内嵌多种卡片视图(ViewPager、RadioGroup)
- Android设计模式之Builder模式详解
- 详解Android获取系统内核版本的方法与实现代码
- Android 修改viewpage滑动速度的实现代码
- 在Ubuntu20.04中安装ROS Noetic的方法
- Android设计模式之单例模式详解
- Android获取手机联系人的方法
- 学习使用Material Design控件(一)
- Android仿微信Viewpager-Fragment惰性加载(lazy-loading)
- Android嵌套滑动冲突的解决方法
- Android应用图标上的小红点Badge实践代码
- 详解Android studio中正确引入so文件的方法
- Android ViewFlipper的详解及实例