我在OP的代码中看不到真正的UB。
可移植性问题:是的。
“类型匹配在其他系统上可能无法正常工作”不是OP的C代码的问题,但可能会引起其他语言的麻烦。
但是要托管一个较大的(PNG)字节序怎么样?
按地址提取字节(具有MSByte的最低地址到具有LSByte的最高地址-“大”字节序),并通过移位后的字节形成结果。
类似的东西:
uint32_t Endian_BigToHost32(uint32_t val) {
union {
uint32_t u32;
uint8_t u8[sizeof(uint32_t)]; // uint8_t insures a byte is 8 bits.
} x = { .u32 = val };
return
((uint32_t)x.u8[0] << 24) |
((uint32_t)x.u8[1] << 16) |
((uint32_t)x.u8[2] << 8) |
x.u8[3];
}
提示:许多库都具有特定于实现的功能来有效地解决此问题。示例be32toh。
,
IMO最好是从字节读取为所需的格式,而不是明显地处理uint32_t然后在内部操作uint32_t。代码可能像这样:
uint32_t read_be32(uint8_t *src) // must be unsigned input
{
return (src[0] * 0x1000000u) + (src[1] * 0x10000u) + (src[2] * 0x100u) + src[3];
}
很容易将这种代码弄错,因此请确保您是从高级代表SO用户处获得的。但是,您可能经常会看到替代建议return (src[0] << 24) + (src[1] << 16) + (src[2] << 8) + src[3];
,如果src[0] >= 128
由于有符号整数溢出而导致uint8_t
会导致不确定的行为,这是由于不幸的规则是整数促销将int
带到有符号{{1 }}。由于移位大,还会在具有16位int的系统上导致不确定的行为。
现代编译器应该足够聪明地进行优化,例如the assembly produced by clang little-endian是:
read_be32: # @read_be32
mov eax,dword ptr [rdi]
bswap eax
ret
但是我发现gcc 10.1产生了更复杂的代码,这似乎是一个令人惊讶的错过的优化错误。
,
此解决方案不依赖于访问联盟的非活动成员,而是依赖于无符号整数位移位操作,该操作可移植并安全地从big-endian转换为little-endian ,反之亦然 >
#include <stdint.h>
uint32_t convertEndian32(uint32_t in){
return ((in&0xffu)<<24)|((in&0xff00u)<<8)|((in&0xff0000u)>>8)|((in&0xff000000u)>>24);
}
,
此代码独立于体系结构的字节序,从大字节序存储中的uint32_t
指针中读取uchar_t
。 (该代码就像读取了一个以256为底的数字一样)
uint32_t read_bigend_int(uchar_t *p,int sz)
{
uint32_t result = 0;
while(sz--) {
result <<= 8; /* multiply by base */
result |= *p++; /* and add the next digit */
}
}
如果您致电,例如:
int main()
{
/* ... */
uchar_t buff[1024];
read(fd,buff,sizeof buff);
uint32_t value = read_bigend_int(buff + offset,sizeof value);
/* ... */
}
本文链接:https://www.f2er.com/2300005.html