回 帖 发 新 帖 刷新版面

主题:[讨论]关于指针的一个怪现象

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

void main(void)
{
    char text[] = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A";
    int * pInt;
    int intV;

    pInt = (int *)&text[1];
    intV = *((int *)&text[1]);
    printf("%08x, %08x\n", *pInt, intV);
}
在VC++ 2005上编译得到我预期的结果:
05040302, 05040302

但在ARM7平台,ADS1.2编译的结果却不一样:
01040302, 01040302

请问,这个与什么有关?
以前写代码,在解析数据流时,常常会把 unsigned char[]的第n个元素的地址直接转化为所需类型的地址,然后直接*取值,今天却碰到这个BUG,晕死,以前都没注意过。

回复列表 (共5个回复)

沙发

这应该不是bug吧?!用C语言写代码常常需要对代码工作平台有一定了解。ARM系列对数据对齐要求较严,访问非对齐的数据一般有三种情况会发生。有一种是:内存中有这样的数据, 01,02,03,04,05,06,07,08。其中 01的地址是4的倍数,然后递增。如果要从02开始读取32位的数据,那么它会从内存中读取01,02,03,04,然后把02循环移位至最低位得02,03,04,01,如果采用little-endian存储将输出01040302,而big-endian存储则02030401。由于没有arm的环境,上面可能是错的。

板凳

多日不见windy0will兄水平进步神速啊。

3 楼

[quote]这应该不是bug吧?!用C语言写代码常常需要对代码工作平台有一定了解。ARM系列对数据对齐要求较严,访问非对齐的数据一般有三种情况会发生。有一种是:内存中有这样的数据, 01,02,03,04,05,06,07,08。其中 01的地址是4的倍数,然后递增。如果要从02开始读取32位的数据,那么它会从内存中读取01,02,03,04,然后把02循环移位至最低位得02,03,04,01,如果采用litter-endian存储将输出01040302,而big-endian存储则02030401。由于没有arm的环境,上面可能是错的。[/quote]
不是这样处理的。如果int类型的地址不是模四的,那么读取这个变量时要读取两次(本地址4字节对齐的地址与下个4字节对齐的地址),再把两次的值合并成结果。x86下是这样做的。
但是我就奇怪为什么ARM7下没有这么做?

4 楼

[quote]多日不见windy0will兄水平进步神速啊。[/quote]
强强兄,您被表面现象蒙蔽了。前几天刚好看了本关于ARM的书,学了些纯理论的东西。我学的那些都只能玩玩而已,没实际用处,想向论坛里大牛们学点真正有用的东西。
强强兄,最近很忙?


=============================================================================
楼主,在IA-32平台确实是您说的那样的。
对于老版本的ARM:
  1. 一次访问4字节内容,该内容的起始地址必须是4字节对齐的位置上;
  2. 一次访问2字节内容,该内容的起始地址必须是2字节对齐的位置上;
如果访问非对齐数据一般会是下面3中情况之一【比如内存中有下面数据:00,01,02,03,04,05,06,07,08(假设内存地址是从0x0到0x7)】,我就举从0x1的地址开始读取4个字节:
  1.无法预测的错误
  2.直接把0x0开始的内容读入,也就是相当于从低地址开始读入0x00010203这4个字节。
  3.就是我在2楼说的那种情况,先读入0x00010203这4个字节,然后把它循环移位,让0x1这个地址对应的字节移位到最低位,这样读入的数据就变成了0x01020300了。

具体为什么会出现那样的结果,您最好把C代码直接编译成汇编代码。我在网上找到的一篇文章,问题和您的问题基本上一摸一样,[url]http://hi.baidu.com/aki%5Fshaw/blog/item/5bd26901affe56004bfb51e3.html[/url].
不过,可能新版本的也支持非对齐的数据访问了吧?但是,绝对会有某款ARM平台的C语言编译器支持非对齐数据的读取,具体实现被编译器给隐藏了。可能您没有把这个功能的开关打开吧?

上面是在书上看到的,我没有用过ARM平台,不能调试,所以不知道是不是正确的。

5 楼

[quote][quote]多日不见windy0will兄水平进步神速啊。[/quote]
强强兄,您被表面现象蒙蔽了。前几天刚好看了本关于ARM的书,学了些纯理论的东西。我学的那些都只能玩玩而已,没实际用处,想向论坛里大牛们学点真正有用的东西。
强强兄,最近很忙?


=============================================================================
楼主,在IA-32平台确实是您说的那样的。
对于老版本的ARM:
  1. 一次访问4字节内容,该内容的起始地址必须是4字节对齐的位置上;
  2. 一次访问2字节内容,该内容的起始地址必须是2字节对齐的位置上;
如果访问非对齐数据一般会是下面3中情况之一【比如内存中有下面数据:00,01,02,03,04,05,06,07,08(假设内存地址是从0x0到0x7)】,我就举从0x1的地址开始读取4个字节:
  1.无法预测的错误
  2.直接把0x0开始的内容读入,也就是相当于从低地址开始读入0x00010203这4个字节。
  3.就是我在2楼说的那种情况,先读入0x00010203这4个字节,然后把它循环移位,让0x1这个地址对应的字节移位到最低位,这样读入的数据就变成了0x01020300了。

具体为什么会出现那样的结果,您最好把C代码直接编译成汇编代码。我在网上找到的一篇文章,问题和您的问题基本上一摸一样,[url]http://hi.baidu.com/aki%5Fshaw/blog/item/5bd26901affe56004bfb51e3.html[/url].
不过,可能新版本的也支持非对齐的数据访问了吧?但是,绝对会有某款ARM平台的C语言编译器支持非对齐数据的读取,具体实现被编译器给隐藏了。可能您没有把这个功能的开关打开吧?

上面是在书上看到的,我没有用过ARM平台,不能调试,所以不知道是不是正确的。

[/quote]
windy0will,谢谢了,你太牛了。请问哪本书里会有这么详细的介绍?

我来回复

您尚未登录,请登录后再回复。点此登录或注册