您的位置 首页 汽车

arm 下C编程的非对齐拜访

看到这个标题,你以为我要讲的是程序中结构体的字节对齐问题,那你就错了,我要讲的是arm下的对于非对齐数据的访问。这个问题把我折腾了一…

看到这个标题,你认为我要讲的是程序中结构体的字节对齐问题,那你就错了,我要讲的是arm下的关于非对齐数据的拜访。这个问题把我折腾了一天啊!

闲话少说了,先贴一个测验的代码,假如有arm开发板的同学能够拿到板子上跑一下,和在x86机器上跑出来的程序成果比照一下。

测验代码

#include #include struct test{unsigned char  a;unsigned char  b;unsigned char  sc;unsigned char  sd;};struct test bbb;int main (int argc, char  argv){char *tmp=(char *)&bbb;printf("sizeof(struct test)=%d \n",sizeof(struct test));bbb.a = 0x01;bbb.b = 0x02;bbb.sc = 0x03;bbb.sd = 0x04;printf("bbb   0x%08x \n",*(unsigned long *)tmp);printf("tmp   %x= 0x%04x \n",(int)tmp,*((unsigned short *)(tmp)));tmp+=1;printf("tmp+1 %x= 0x%04x \n",(int)tmp,*((unsigned short *)(tmp))); tmp+=1;printf("tmp+2 %x= 0x%04x \n",(int)tmp,*((unsigned short *)(tmp)));  }

成果出人意料(假如你不知道),居然成果不同。

问题剖析:

咱们假定变量bbb在内存中是这样散布的

0x1000 0x01
0x1001 0x02
0x1002 0x03
0x1003 0x04

1、tmp开端的时分是指向0x1000的,取将tmp强制转化为unsigned short 后输出地值为0x0201,这个没问题。

2、将tmp向后移动一位到0x1001后,取将tmp强制转化为unsigned short 后输出地值,这儿,在x86和arm上跑的时分,就呈现了不同的值了

在x86机器上跑出来的值是0x0302,这个是咱们所期望的;可是在arm上这个值是0x0201。回去了?!

与其他RISC架构相同,ARM处理器能够高效地拜访对齐的数据,即字地址的结尾两位为零,半字地址的最终一位为零,也称这样的数据坐落它的天然巨细鸿沟或许是天然对齐的。ARM编译器期望一般的“C”指针指向一个4字节对齐内存地址,这样它能够在代码中运用LDR/STR指令一次操作4个字节,不然只能运用LDRB/LDRH等字节/半字操作指令。相反假如指针指向一个非天然对齐的地址,例如假如一个整型指针指向地址0x8006,当然期望装载地址0x8006-0x8007-0x8008-0x8009处的数据,可是实际上ARM会对非天然对齐的地址进行转化而从装载地址 0x8004-0x8005-0x8006-0x8007处的数据。

3、假如是long型的强制转化,

long *tmp_long=(long *)tmp;

假如现在tmp指向的是0x1002,*tmp_long会是什么值呢?在x86下可能会呈现段过错,由于内存越界了,假如没有的话,输出应该是0x00000403;

在arm下输出的成果是0x02010304,这个我没太想理解。我看网上有的说是循环移位的成果,这个循环移位以字节。假如是这个姿态的话,那么short类型为什么不是循环移位啊?想不理解啊。

总结:

关于arm中的双字节或许4字节数据的拜访,不能直接经过数据类型的强制转化来完成,有必要经过单字节的方法:运用单字节赋值,或许memcpy等函数,不过这样做的时分,首先要先确认数据是大端仍是小端形式。

例如上面的数据,需求取出long型,能够这样做

long tmp_long;memcpy(&tmp_long,tmp,4);

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/276708.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部