Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.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 嵌入式系统上的指针转换,32位变量上的字节指针通过指针转换_C_Pointers_Casting_Embedded_Byte - Fatal编程技术网

C 嵌入式系统上的指针转换,32位变量上的字节指针通过指针转换

C 嵌入式系统上的指针转换,32位变量上的字节指针通过指针转换,c,pointers,casting,embedded,byte,C,Pointers,Casting,Embedded,Byte,我必须读出uint32_t变量的字节,我看到了这种情况 由我的一位同事执行。我的问题是,如果代码示例的行为在“几乎每”32位上都是可靠的 微控制器。它是否可以在每个32位微控制器上工作,或者是我所依赖的特定于平台的行为? 注意:本例中不考虑系统的端部 uint8_t byte0=0; uint8_t byte1=0; uint8_t byte2=0; uint8_t byte3=0; uint8_t *byte_pointer; //byte_point

我必须读出uint32_t变量的字节,我看到了这种情况 由我的一位同事执行。我的问题是,如果代码示例的行为在“几乎每”32位上都是可靠的 微控制器。它是否可以在每个32位微控制器上工作,或者是我所依赖的特定于平台的行为? 注意:本例中不考虑系统的端部

uint8_t     byte0=0;
uint8_t     byte1=0;
uint8_t     byte2=0;
uint8_t     byte3=0;
uint8_t     *byte_pointer;  //byte_pointer
uint32_t    *bridge_pointer;//pointer_bridge between 32bit and 8 bit variable
uint32_t    var=0x00010203;

bridge_pointer=&var;    //bridge_pointer point to var
byte_pointer=(uint8_t *)(bridge_pointer);   //let the byte_pointer point to bridge_pointer

byte0=*(byte_pointer+0);    //saves byte 0
byte1=*(byte_pointer+1);    //saves byte 1
byte2=*(byte_pointer+2);    //saves byte 2
byte3=*(byte_pointer+3);    //saves byte 3
提前谢谢

byte0=*(byte_pointer+0);    //saves byte 0
这一行(以及下面的几行)违反了严格的别名。声明为
uint32\u t
的对象通过类型为
uint8\u t
的左值访问<应该使用code>无符号字符而不是
uint8\u t
,因为允许字符类型的左值访问不同类型的对象(如果
uint8\u t
存在,则其行为与
无符号字符
相同,尽管有更宽松的别名规则)

如a中所述,
字节指针[0]
相当于
*(字节指针+0)
,更常见

通过此更改,代码具有定义良好的行为。(并且可移植到具有
uint32_t
uint8_t
的实现中,尽管endianness可能会导致不同的结果,如问题中所述。)


严格别名的相关标准部分是6.5 p6/7。

您应该将
字节指针
声明为
无符号字符*
,如果您在little endian上接受不同的输出,那么您的示例将起作用。这里有一个解决方案,它不依赖于持久性

uint8_t byte0 = var;
uint8_t byte1 = var>>8;
uint8_t byte2 = var>>16;
uint8_t byte3 = var>>24;

字节0
将是LSB

在实践中,代码是可移植的,除了endianess问题。在标准之外的现实世界中,通过uint8_t指针访问uint32_t的一部分始终有效

,但这种讨论只是学术上的兴趣。(如果将其视为字符类型,则不会破坏标准6.5/7中的别名规则。)实际上,uint32_t将不包含任何填充位或标准允许的其他此类理论无意义


为了避免端性问题,我建议重新编写代码以使用位移位,正如@mch的回答中所演示的那样。

byte0=byte\u指针[0]
等将更加优雅(相当于
*(byte\u指针+0)
)。另外,我认为绝对没有必要使用
桥接指针
,您可以立即将
&var
转换为
uint8*
。您可能想了解和。谢谢您的回答,这对我很有帮助。其他答案也很有用,谢谢。实际上,
uint8\u t
的行为与无符号字符完全相同,因此不会破坏严格的别名@Lundin:IIRC gcc邮件列表在不久前讨论过这个问题,它被认为是gcc中的一个bug,它没有使用别名信息,可能会发生更改。我不确定目前的状况。我找到后会链接。@Lundin:对不起,我再也找不到了。在对R的回答的评论中提到了这一点。也许我会在接下来的几天里找到它。除此之外,我真的认为,
无符号字符
应该在这里使用。这个UB可能有助于优化,我们应该假设它会被使用。(当Gcc使用带符号整数溢出的UB时,根据“这在现实中有效,所以不必在意”的推理导致代码中断,根本不进行别名分析,取消对
NULL
指针的引用,…)@Lundin:例如,邮件列表中提到了这一点。找不到更好(更新)的参考资料。正如我所说,我不知道目前的状况。但是标准是明确的,有优化的机会,所以有一天一些编译器可能会利用它。”[…]填充位或其他标准允许的理论上的胡说八道。”--它没有。参见C11(n1520)7.20.1.1 p1/2。
(u)intN\u t
类型的行为相当“正常”:2的补码,没有填充位。@mafso所以没有理由说uint8\u t不起作用。@Lundin:标准允许实现使用32位中的任何一位!(即,大约2.63E+35)将
uint32_t
的位映射到四个连续uint8_t值的位的方法。在实践中,两个映射比任何其他映射都要常见得多,并且在任何非人为实现中可能最多出现两个以上的映射。
uint8_t byte0 = var;
uint8_t byte1 = var>>8;
uint8_t byte2 = var>>16;
uint8_t byte3 = var>>24;