c/c++语言开发共享在嵌入式设备上投射指针

在32位嵌入式系统上投射和修改指针时遇到了一个奇怪的问题(运行contiki OS的 redbee econotag是特定的)。

uint32_t array[2]; array[0] = 0x76543210; array[1] = 0xfedcba98; uint8_t* point = ((uint8_t*)array)+1; printf("%08x n", *(uint32_t*)point ); 

在我的电脑上输出:

 98765432 

嵌入式设备上的输出:

 10765432 

我的计算机的行为与我期望的一样,但嵌入式设备似乎在它到达单词的末尾时回滚。 为什么会这样?

    您的目标“redbee econotag”被声明为具有ARMv4架构的ARM7。 ARMv4不提供像ARMv7或intel机器那样的未对齐内存访问。

    引用ARM的文档 :

    在ARMv4和ARMv5体系结构以及ARMv6体系结构(取决于其配置方式)上,在访问内存中的未对齐数据时需要小心,以免返回意外结果。 例如,当传统指针用于读取C或C ++源代码中的单词时,ARM编译器生成使用LDR指令读取单词的汇编语言代码。 当地址是四的倍数时,这可以正常工作,例如,如果它位于单词边界上。 但是, 如果地址不是4的倍数,则LDR返回旋转结果,而不是执行真正的未对齐字加载。 通常,这种旋转不是程序员所期望的

    使用此代码,您将破坏严格别名规则:由point的对象由具有uint32_t类型的左值表达式访问。

    C11(n1570),§6.5表达式
    对象的存储值只能由具有以下类型之一的左值表达式访问:
    – 与对象的有效类型兼容的类型,
    – 与对象的有效类型兼容的类型的限定版本,
    – 对应于对象的有效类型的有符号或无符号类型,
    – 对应于对象有效类型的限定版本的有符号或无符号类型,
    – 聚合或联合类型,其成员中包含上述类型之一(包括递归地,子聚合或包含联合的成员),或者
    – 一个字符类型。

    这会导致未定义的行为,因此任何事情都可能发生。

    C11(n1570),§4。一致性
    如果违反约束或运行时约束之外的“应该”或“不应该”的要求,则行为未定义。

     printf("%08x n", *(uint32_t*)point ); 

    此语句中的*表达式调用未定义的行为:它违反了别名规则,可能会执行未对齐的访问。

    由于+1您执行32位值的未对齐访问,即地址不是4的倍数。

    x86独立于对齐工作,因为它的根源一直回到8位机器(可能性能稍差)。

    ARM需要对齐(与许多其他处理器一样),因此应将32位值放在四个字节的倍数的地址上。 如果不是这种情况,可能会发生各种不好的事情(错误的值,错误)。 对于数组,编译器会处理这个问题,但是当您显式地转换指针时,会强制它违反对齐。

    编辑:请注意,这个答案的主体与它提示的评论无关

    其他答案的理论很好,但可能对你没有帮助。 实际的问题是你写道:

     uint8_t* point = ((uint8_t*)array)+1; 

    什么时候你应该写一些像

     uint8_t* point = (uint8_t*)(array+1); 

    因为您需要将指针增加为指向适当类型的指针(以便增量操作将添加元素的大小),然后再将其转换为其他内容。

    但有人可能会问你是否真的想要一个指向32位值的字节指针。 也许你打算以字节方式访问它(请注意字节顺序会因系统而异!)。 或者你真的打算指向一个32位值的指针,而这个指针又是指向其他地方的8位值的指针……

      以上就是c/c++开发分享在嵌入式设备上投射指针相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/545781.html

      (0)
      上一篇 2021年1月10日
      下一篇 2021年1月10日

      精彩推荐