Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在嵌入式设备上强制转换指针_C_X86_Embedded_Arm_Contiki - Fatal编程技术网

C 在嵌入式设备上强制转换指针

C 在嵌入式设备上强制转换指针,c,x86,embedded,arm,contiki,C,X86,Embedded,Arm,Contiki,在32位嵌入式系统上强制转换和修改指针时,我遇到了一个奇怪的问题(具体来说是运行) 我的计算机上的输出: 98765432 嵌入式设备上的输出: 10765432 我的电脑的工作方式和我预期的一样,但是当它到达单词的末尾时,嵌入式设备似乎就开始运转了。为什么会发生这种情况 printf("%08x \n", *(uint32_t*)point ); 此语句中的*表达式调用了未定义的行为:它违反了别名规则,可能会进行未对齐的访问。使用此代码,您打破了严格的别名规则:点所指向的对象由具有uin

在32位嵌入式系统上强制转换和修改指针时,我遇到了一个奇怪的问题(具体来说是运行)

我的计算机上的输出:

98765432
嵌入式设备上的输出:

10765432
我的电脑的工作方式和我预期的一样,但是当它到达单词的末尾时,嵌入式设备似乎就开始运转了。为什么会发生这种情况

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

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

使用此代码,您打破了严格的别名规则:
点所指向的对象由具有
uint32\t
类型的左值表达式访问

C11(n1570),§6.5表达式 对象的存储值只能由具有以下类型之一的左值表达式访问:
-与对象的有效类型兼容的类型,
-与对象的有效类型兼容的类型的合格版本,
-一种类型,它是与数据的有效类型相对应的有符号或无符号类型 对象,
-一种类型,该类型是与文件的合格版本相对应的有符号或无符号类型 对象的有效类型,
-一种聚合或联合类型,其中包括上述类型之一 成员(递归地包括子集合或包含的联合的成员),或
-字符类型

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

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


编辑:请注意,此答案的正文因其提示的评论而变得无关紧要

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

uint8_t* point = ((uint8_t*)array)+1;
当你应该写一些东西的时候,比如

uint8_t* point = (uint8_t*)(array+1);
因为您需要将指针作为指向适当类型的指针递增(以便递增操作将添加元素的大小),然后再将其强制转换为其他类型


但有人可能会问,您是否真的想要一个指向32位值的字节指针。也许您确实打算以字节方式访问它(请注意,不同系统的字节顺序会有所不同!)。或者,您可能真的打算将点作为指向32位值的指针,而32位值反过来又是指向其他地方8位值的指针…

因为
+1
您对32位值进行未对齐访问,即地址不是四的倍数

x86独立于对齐工作,因为它的根可以追溯到8位机器(可能性能稍差)

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

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

引述自:

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


我收到一个char*,它指向AES寄存器的32位值。char*不能是另一种类型,因为它指向内存中在AES块前面有可变字节数的区域。由于这是一款低功耗的嵌入式davice,因此使用尽可能少的内存和能量(操作)是有利的。虽然针对特定情况可能会有更多的最佳解决方案,但想到的最简单的事情是将字节复制到对齐的位置。但是,这实际上取决于未对齐的源数据是否以系统的endian顺序存储。如果没有,您可能需要以字节方式访问数据,然后以算术方式将其重新组合为32位字™ 要做到这一点,需要将字节以32位的值逐个移动到正确的位置。指针强制转换或使用union进行类型转换等肮脏的技巧会让您直接进入可移植性地狱。@starblue-请重新阅读建议内容,因为只涉及正确的访问,而不涉及此类“肮脏的技巧”。如何处理可移植性取决于对源端性的了解——如果它是绝对已知的(网络协议等),则可以使用显式组合来形成目标值。但是如果只知道它与目的地相同,那么最好使用字节复制。@Chris Stratton在你写的时候,“字节复制到对齐的位置”会在端点改变时咬到你,所以不要这样做。“以字节方式访问数据,然后以算术方式将其重新组合成32位字”是唯一干净的解决方案,因为编译器会处理所有不干净的细节。这个答案是上述代码的另一个错误(如果大多数编译器都能让您逃脱的话),但这不是所述行为的原因。原因是将字节对齐的值强制转换为4字节对齐的指针-
uint8_t* point = (uint8_t*)(array+1);