arm 下C编程的非对齐访问

3 篇文章 0 订阅
2 篇文章 0 订阅

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

闲话少说了,先贴一个测试的代码,如果有arm开发板的同学可以拿到板子上跑一下,和在x86机器上跑出来的程序结果对比一下。

测试代码

 #include <stdio.h>
 #include <stdlib.h>


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在内存中是这样分布的

0x10000x01
0x10010x02
0x10020x03
0x10030x04

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);



 

 

 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值