ARM下的对齐处理   
from DUI0067D_ADS1_2_CompLib

3.13 type  qulifiers

有部分摘自ARM编译器文档对齐部分  
对齐的使用:  
1.__align(num)  
   这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时  
   就要用到此命令__align(8)进行修饰限制,来保证数据对象是相应对齐。  
   这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节  
   对齐,但是不能让4字节的对象2字节对齐。  
   __align是存储类修改,他只修饰最高级类型对象,不能用于结构或者函数对象。

比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];//保证分配的数组空间4字节对齐,同时保证数组首地址可被4整除
     
2.__packed   
  __packed是进行一字节对齐  
  1.不能对packed的对象进行对齐  
  2.所有对象的读写访问都进行非对齐访问  
  3.float及包含float的结构联合及未用__packed的对象将不能字节对齐  
  4.__packed对局部整形变量无影响  
  5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定  
  义为packed。  
     __packed int* p;  //__packed int 则没有意义  
  6.对齐或非对齐读写访问带来问题  
  __packed struct STRUCT_TEST  
{  
  char a;  
  int b;  
  char c;  
}  ;    //定义如下结构此时b的起始地址一定是不对齐的  
         //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL]  
//将下面变量定义成全局静态不在栈上   
static char* p;  
static struct STRUCT_TEST a;  
void Main()  
{  
__packed int* q;  //此时定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以

p = (char*)&a;            
q = (int*)(p+1);

*q = 0x87654321;   
/*     
得到赋值的汇编指令很清楚  
ldr      r5,0x20001590 ; = #0x12345678  
[0xe1a00005]   mov      r0,r5  
[0xeb0000b0]   bl       __rt_uwrite4  //在此处调用一个写4byte的操作函数   
        
[0xe5c10000]   strb     r0,[r1,#0]   //函数进行4次strb操作然后返回保证了数据正确的访问  
[0xe1a02420]   mov      r2,r0,lsr #8  
[0xe5c12001]   strb     r2,[r1,#1]  
[0xe1a02820]   mov      r2,r0,lsr #16  
[0xe5c12002]   strb     r2,[r1,#2]  
[0xe1a02c20]   mov      r2,r0,lsr #24  
[0xe5c12003]   strb     r2,[r1,#3]  
[0xe1a0f00e]   mov      pc,r14  
*/

/*  
如果q没有加__packed修饰则汇编出来指令是这样直接会导致奇地址处访问失败  
[0xe59f2018]   ldr      r2,0x20001594 ; = #0x87654321  
[0xe5812000]   str      r2,[r1,#0]  
*/

//这样可以很清楚的看到非对齐访问是如何产生错误的  
//以及如何消除非对齐访问带来问题  
//也可以看到非对齐访问和对齐访问的指令差异导致效率问题  
}

比如:

typedef __packed struct READ_Command
{
    u_char code;
    u_int addr;
    u_char len;
} READ_Command;

typedef  struct READ_Command
{
    u_char code;
    u_int addr;
    u_char len;
} READ_Command;
的区别是什么啊?
回答:没有__packed的会出现字对齐等也就是,char型的有可能是占用4个字节的长度的内存空间有__packed 的就不会,就肯定是1个字节的内存空间,是gcc编译器的关键字。(不止vc下面32位的系统里面的内存数据的存取是32位的,处理的时候都是4个字节为单位,通常也就是int的长度。如果不定义压缩方式,也就是编译选项没有诸如#pragma pack(1)之类的,那么系统会进行4字节对齐)
注意:_packed只是某种编译器的格式压缩,有的是pack呢,对不同的CPU压缩的对齐方式也不一样,在使用了该关键以后在进行操作时需要格外小心。
声明结构类型时,可以包含一个保留字packed,用于实现压缩数据存储。
      当一个记录类型在   {$A-}   状态下声明或者声明中包括了保留字   packed   时,记录中的字段不被调整,而替换为赋予连续的偏移量。这样一个压缩记录的总尺寸就是所有字段的尺寸的和。因为数据调整尺寸可能改变(如不同版本的编译器对同一种数据类型的调整值可能不同),所以当想要把记录写入磁盘时或者在内存中传递到另一模块而该模块由不同版本的编译器编译时,最好还是压缩所有的记录。(delphi borland 中也有该关键字)
 
3.在 Cotex-M3 programming manual 中有提到对齐问题
  1.通常编译器在生成代码的时候都会进行结构体填充,保证(结构体内部成员)最高性能的对齐方式。
  2.编译器自动分配出来结构体的内存(比如定义为全局变量或局部变量)肯定是对齐的。
  3.查阅帮助文档的malloc部分,mdk的标准malloc申请的内存区时8字节对齐的。
  4.若自定义的malloc函数本身没有对分配的内存实现4字节或以上的对齐操作,分配出来的不对齐的内存,编译器是不知道的,所以很可能会产生问题。
     此时最好的解决方式在内存池数组前添加__align(4)关键字,只需保证自定义malloc分配出来的首地址是4字节对齐。
     比如:__align(4) u8 mem1base[MEM1_MAX_SIZE];
 
相关更多stm32字节对齐问题的讨论,请参考正点原子相关帖子http://www.openedv.com/thread-7415-1-1.html。
其中问题的关键就在于正点原子自定义的mymalloc函数没有实现4字节对齐。

stm32中字节对齐问题(__align(n),__packed用法)的更多相关文章

  1. c++内存中字节对齐问题详解

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

  2. keil mdk+stm32的ac5和 ac6两个编译器下的字节对齐操作方法

    最近在使用ac6.9的编译器,编译速度是真的很快,使用stm32的hal库编译速度也比ac5的编译器快很多.本文试验stm32中字节对齐的代码测试,主要是结构体,因为结构体中实际项目中用到最多,同时在 ...

  3. ARM字节对齐问题详解

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

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

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

  5. C语言字节对齐问题详解(对齐、字节序、网络序等)

    首先说明一下,本文是转载自: http://www.cnblogs.com/clover-toeic/p/3853132.html 博客园用的少,不知道怎么发布转载文章,只能暂时这样了. 引言 考虑下 ...

  6. struct 字节对齐详解

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

  7. C语言字节对齐问题详解【转】

    引言 转自:http://www.cnblogs.com/clover-toeic/p/3853132.html 考虑下面的结构体定义: 1 typedef struct{ 2 char c1; 3 ...

  8. [转]C语言字节对齐问题详解

    C语言字节对齐问题详解 转载:https://www.cnblogs.com/clover-toeic/p/3853132.html 引言 考虑下面的结构体定义: typedef struct{ ch ...

  9. C语言结构体的字节对齐原则

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

随机推荐

  1. java离线地图web GIS制作

    因为项目需求,要做一个web地图,之前做过高德的在线地图,它提供了一系列的API,并且由于是国产的,所以开发起来比较容易,现在由于项目是内网使用的,所以需要使用离线地图,由此便开始了: Web GIS ...

  2. BZOJ4569 SCOI2016萌萌哒(倍增+并查集)

    一个显然的暴力是用并查集记录哪些位之间是相等的.但是这样需要连nm条边,而实际上至多只有n条边是有用的,冗余过多. 于是考虑优化.使用类似st表的东西,f[i][j]表示i~i+2^j-1与f[i][ ...

  3. ef group 封装

    表达式树,传递 group public class Test<T> where T : class { MoviesEntities db = new MoviesEntities(); ...

  4. emwin之GUIBuilder使用控件命名技巧

    @2018-07-30 使用emwin-GUIBuilder布局界面时,各控件命名技巧及规则如下图所示(遵循此规则在写代码时好处多多) > 如上图所示所使用的第一组控件分别为 Text.Edit ...

  5. js的==和===练习

    今天检查了一下JS的== 和===的区别 如下: 表达式                              值 1==true  true 1===true  false 0==false t ...

  6. SimpleDateFormat是线程不安全的,切忌切忌!

    多线程方法中使用了共享变量SimpleDateFormat,报如下错误: java.lang.NumberFormatException: multiple points  at sun.misc.F ...

  7. qrcode模块简单使用

    函数式自动生成二维码 import qrcode img = qrcode.make("hello world!") img.get_image().show() img.save ...

  8. Service 启动Activity

    1, 在BroadcastReceiver中启动Activity的问题  *  * 如果在BroadcastReceiver的onReceive()方法中如下启动一个Activity  * Inten ...

  9. [luogu4462][异或序列]

    传送门 突然发现自己没整理过异或的知识,正好借这个题整理一下. 关于异或 (1)异或就是在二进制下,两数各个位置上的数,相同为0,不同为1,所得到的数,比如说4^7,4的二进制是100,7的二进制是1 ...

  10. Gradle 从svn 中检出的父项目后处理配置【我】

    前提: 一个用gradle配置的 类似maven的聚合项目的项目,然后它在svn上就是一个父工程的目录. 检出方式: 在eclipse中,直接用svn资源库检出 父项目 的目录. 然后,在父项目下面的 ...