我必须读出uint32_t变量的字节,我已经看到了这种情况 我的一位同事的实施。我的问题是,如果该代码示例的行为在"几乎所有" 32位 微控制器。是否可以在每个32位微控制器上工作,还是我依赖的平台特定行为? P.S。:在这个例子中不应该考虑系统的字节序。
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
先谢谢
答案 0 :(得分:4)
您应该将byte_pointer
声明为unsigned char*
,如果您在小端接受不同的输出,那么您的示例将起作用。这是一个解决方案,它不依赖于endianess
uint8_t byte0 = var;
uint8_t byte1 = var>>8;
uint8_t byte2 = var>>16;
uint8_t byte3 = var>>24;
byte0
将成为LSB
答案 1 :(得分:3)
byte0=*(byte_pointer+0); //saves byte 0
此行(以及以下行)违反严格别名。声明为uint32_t
的对象是通过类型uint8_t
的左值访问的;应使用unsigned char
而不是uint8_t
,因为允许字符类型的左值访问不同类型的对象(如果存在uint8_t
,则其行为与unsigned char
相同尽管有更宽松的锯齿规则)。
unsigned char *byte_pointer = (unsigned char *)(bridge_pointer);
uint8_t byte0 = *(byte_pointer+0);
// byte0 can still be uin8_t, the access to var is important for aliasing
如comment中所述,byte_pointer[0]
相当于*(byte_pointer+0)
,更为常见。
通过此更改,代码具有明确定义的行为。 (并且可以移植到具有uint32_t
和uint8_t
的实现,虽然字节顺序可能导致不同的结果,如问题中所述。)
严格混叠的相关标准部件为6.5 p6 / 7.
答案 2 :(得分:1)
实际上,除了字节序问题外,代码都是可移植的。通过uint8_t指针访问uint32_t的一部分将始终在标准之外的现实世界中工作。
Whether uint8_t is considered a character type or not is debated,但这个讨论仅仅是学术界的兴趣。 (如果要将其视为字符类型,则不会在标准6.5 / 7中使用中断别名规则。)实际上,uint32_t将不包含任何填充位或标准允许的其他理论无意义。
为了避免语句问题,我建议重新编写代码以使用位移,这在@ mch的答案中已被证明。