问题由来:pc的lsb总是0,因为代码至少要字对齐。cm3的指令至少是半字对齐的(16)

一、啥是字对齐?为啥要字对齐?

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

字节对齐的原因大致是如下两条:

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

二、对齐规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
规则:
1. 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
2. 结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
3. 结合1、2可推断:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。

三、X86对齐实验
       下面再简要回顾解释一下上述的对齐规则,结合实例进行分析:
1. 数据类型自身的对齐值:对于char型数据,其自身对齐值为1字节,对于short型为2字节,对于int,float,double类型,其自身对齐值为4字节。
2. 结构体的自身对齐值:其成员中自身对齐值最大的那个值。
3. 指定对齐值:#pragma   pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况,第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。
4. 数据成员和结构体的有效对齐值:数据成员(数据类型)和数据结构的自身对齐值和指定对齐值中小的那个值,数据成员对齐了数据结构自然也就对齐了。
了解上述四个基本概念,我们开始讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0"。而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍)。下面结合VS2005中编译环境的例子进行深入了解:
例子B分析:
struct B
{
char b;
int a;
short c;
};
假设B从地址空间0x0000开始排放。该例中没有显式指定对齐值N,VS2005默认值为4。
成员变量b自身对齐值是1,比指定或默认指定对齐值4小,故有效对齐值为1,其存放地址0x0000符合0x0000%1=0,满足字节对齐原则。
成员变量a自身对齐值为4,和指定或默认指定对齐值4相等,故有效对齐值也为4,为了保证字节对齐,成员变量a只能存放在起始地址为0x0004到0x0007这四个连续的字节空间中,复核0x0004%4=0。
成员变量c自身对齐值为2,比指定或默认指定对齐值4小,故有效对齐值为2,可顺序存放在0x0008至0x0009两个字节空间中,符合0x0008%2=0。
至此满足了数据成员的字节对齐,接着看数据结构B的对齐。数据结构B的自身对齐值为其变量中最大对齐值(也就是成员变量b)4,故结构体B的有效对齐值也是4。根据结构体圆整的要求, 0x0009到0x0000=10字节,(10+2)%4=0。所以0x0000A到0x000B也为结构体B所占用。故B从0x0000到0x000B 共有12个字节,sizeof(struct B)=12。
之所以在变量C补充2字节,是因为要实现编译器快速有效的存取结构数组,试想如果定义B结构数组,第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果不把结构的大小补充为对齐值(4)的整数倍,那下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了。
例子C分析:

__align(2) struct C
{
char b;
int a;
short c;
};
   同理,例子C中成员变量b自身对齐值为1,指定对齐值为2,故效对齐值为1,假设C从0x0000开始,那么b存放在0x0000,符合0x0000%1= 0,满足字节对齐原则。
   成员变量a自身对齐值为4,指定对齐值为2,故有效对齐值为2,顺序存放在0x0002、0x0003、0x0004、0x0005四个连续字节中,符合0x0002%2=0,满足字节对齐原则。
   成员变量c的自身对齐值为2,与指定对齐值相等,故有效对齐值为2,顺序存放在0x0006、0x0007中,符合 0x0006%2=0,满足字节对齐原则。
   从0x0000到0x00007共八字节存放的是结构体C的变量。结构体C自身对齐值为4,比指定对齐值2大,故C的有效对齐值为2,因8%2=0,C只占用0x0000到0x0007的八个字节。所以sizeof(struct C)=8,完全满足字节对齐原则。
   除了指定的对齐值不同能导致数据结构的地址存放不同外, 编译器不同存放结构体方式也可能不同。

四、ARM平台的对齐问题

在ARM中,有ARM和Thumb两种指令。

ARM指令:每执行一条指令,PC的值加4个字节(32bits).一次访问4字节内容,该字节的起始地址必须是4字节对齐的位置上,即地址的低两位为bits[0b00],也就是说地址必须是4的倍数。

Thumb指令:每执行一条指令,PC的值加2个字节(16bits).).一次访问2字节内容,该字节的起始地址必须是2字节对齐的位置上,即地址的低两位为bits[0b0],也就是说地址必须是2的倍数。

遵循以上方式叫对齐(aligned)方式,不遵守这样方式称为非对齐(unaligned)的存储访问操作。

五、ARM平台字节对齐关键字
1. __align(num)
   用于修改最高级别对象的字节边界。
A、在汇编中使用LDRD或者STRD时,就用到此命令__align(8)进行修饰限制。来保证数据对象是相应对齐。
B、该修饰对象的命令最大是8个字节限制,可让2字节的对象进行4字节
   对齐,但是不能让4字节的对象2字节对齐。
C、 __align是存储类修改,他只修饰最高级类型对象不能用于结构或者函数对象。
   
2. __packed 
__packed是进行一字节对齐。
A、不能对packed的对象进行对齐;
B、所有对象的读写访问都进行非对齐访问;
C、float及包含float的结构联合及未用__packed的对象将不能字节对齐;
D、__packed对局部整形变量无影响;
D、强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定
义为packed __packed int* p; //__packed int 则没有意义。

3. __unaligned
   用于修饰该变量可按照非对齐访问。

六、如何查找与字节对齐方面的问题
如果出现对齐或者赋值问题首先查看:
1. 编译器的big little端设置;
2. 看这种体系本身是否支持非对齐访问;
3. 如果支持看设置了对齐与否,如果没有则看访问时需要加某些特殊的修饰来标志其特殊访问操作。
七、结论
   针对于32位处理器对于本地使用的数据结构,为提高内存访问效率,采用四字节对齐方式;同时为了减少内存的开销,合理安排结构成员的位置,减少四字节对齐导致的成员之间的空隙,降低内存开销。
   对于处理器之间的数据结构,需要保证消息的长度不因为在不同编译平台和不同处理器导致消息结构的长度发生变化,使用一字节对齐方式对消息结构进行紧缩;为保证处理器之间的消息的数据结构的内存访问效率,采用字节填充的方式自己对消息中成员进行四字节对齐。
   数据结构的成员位置要兼顾成员之间的关系、数据访问效率和空间利用率。顺序安排的原则是:四字节的放在最前面,两字节的紧接最后一个四字节成员,一字节紧接最后一个两字节成员,填充字节放在最后。举例如下:
typedef struct tag_T_MSG{
long ParaA;
long ParaB;
short ParaC;
char ParaD;
char Pad;
} T_MSG;

arm的字节对齐问题总结(转)的更多相关文章

  1. 关于arm 的字节对齐

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

  2. 字节对齐导致的iOS EXC_ARM_DA_ALIGN崩溃

    本文原链接: http://www.cnblogs.com/zouzf/p/4455167.html 先看一下这个链接:http://www.cnblogs.com/ren54/archive/201 ...

  3. ARM字节对齐问题详解

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

  4. 关于arm处理器 内存编址模式 与 字节对齐方式 (转)

    转自:http://bavon.bokee.com/5429805.html 在x86+Linux上写的程序,在PC机上运行得很好.可是使用ARM的gcc进行交叉编译,再送到DaVinci目标板上运行 ...

  5. ARM编译器4字节对齐

    (1)我们假设只有一个赋初值的char型全局变量,那么系统会在data区分配一个4字节的存储空间来存储它.实际上,只用了1个字节,但是为了4字节对齐,只好分配4个字节,所以就会有3个字节浪费. (2) ...

  6. C语言深入学习系列 - 字节对齐&内存管理

    用C语言写程序时需要知道是大端模式还是小端模式. 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中:所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高 ...

  7. cortexm内核 栈的8字节对齐及关键字PRESERVE8

    一.什么是栈对齐? 栈的字节对齐,实际是指栈顶指针须是某字节的整数倍.因此下边对系统栈与MSP,任务栈与PSP,栈对齐与SP对齐 这三对概念不做区分.另外下文提到编译器的时候,实际上是对编译器汇编器连 ...

  8. stm32中字节对齐问题(__align(n),__packed用法)

    ARM下的对齐处理   from DUI0067D_ADS1_2_CompLib 3.13 type  qulifiers 有部分摘自ARM编译器文档对齐部分  对齐的使用:  1.__align(n ...

  9. C语言字节对齐问题详解

    引言 考虑下面的结构体定义: typedef struct{ char c1; short s; char c2; int i; }T_FOO; 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始 ...

随机推荐

  1. [REDIS 读书笔记]第一部分 数据结构与对象 跳跃表

    下面是跳跃表的基本原理,REDIS的实现大致相同 跳跃表的一个特点是,插入NODE是通过随机的方式来决定level的,比较奇特 下面是skipList的一个介绍,转载来的,源地址:http://ken ...

  2. CSS选择器世界

    CSS选择器世界 CSS选择器的分类与优先级 css选择器分为四类:选择器.选择符(后代关系的空格.>.+.~.||).伪类.伪元素(::before.::after.::first-lette ...

  3. Vue简介与基础

    一.什么是Vue.js Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机App, Vue语法也是可以用于进行手机App开发的,需要借助于 ...

  4. 曹工说Spring Boot源码(20)-- 码网灰灰,疏而不漏,如何记录Spring RedisTemplate每次操作日志

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean ...

  5. toj 4353 Estimation(树状数组+二分查找)

    Estimation 时间限制(普通/Java):5000MS/15000MS     运行内存限制:65536KByte总提交: 6            测试通过: 1 描述 “There are ...

  6. 「Flink」使用Java lambda表达式实现Flink WordCount

    本篇我们将使用Java语言来实现Flink的单词统计. 代码开发 环境准备 导入Flink 1.9 pom依赖 <dependencies> <dependency> < ...

  7. Python——捕获异常

    一.什么是异常 """异常:错误,bug处理异常:尝试执行某句可能出现异常的语句, 若出错则用正确的代码去替代. try: 可能发生错误的代码except: 如果出现异常 ...

  8. window10家庭版解决IIS中万维网服务的安全性中无Windows身份验证

    首先在左下角输入cmd搜索->命令提示符->以管理员身份运行->然后复制下面一段命令: dism /online /norestart /add-package:%SystemRoo ...

  9. for _ in range(n) python里那些奇奇怪怪的语法糖

    for _ in range(n)中 _ 是占位符, 表示不在意变量的值 只是用于循环遍历n次. 例如在一个序列中只想取头和尾,就可以使用_ 其实意思和for each in range(n)是一个意 ...

  10. Umi 小白纪实(一)—— 创建项目&常用配置

    umi 是一个企业级 react 应用框架,也是蚂蚁金服的底层前端框架 <蚂蚁金服的前端框架和工程化实践> 一.安装脚手架 在创建项目之前,需要保证有 node 8.10 以上的环境 可以 ...