[英]Is it safe to pass a uint64_t containing a 32-bit value to an external function whose parameter is actually a uint32_t?
[英]Undefined high-order of uint64_t while shifting and masking 32-bit values
我在看似无害的函数中有一些未定义的行为,该函数正在解析缓冲区中的double
值。 我读了double
成两半,因为我是相当肯定的语言标准说换挡char
值仅在32位的情况下有效。
inline double ReadLittleEndianDouble( const unsigned char *buf )
{
uint64_t lo = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
uint64_t hi = (buf[7] << 24) | (buf[6] << 16) | (buf[5] << 8) | buf[4];
uint64_t val = (hi << 32) | lo;
return *(double*)&val;
}
由于我将32位值存储到64位变量lo
和hi
,因此我可以合理地期望这些变量的高32位始终为0x00000000
。 但有时它们包含0xffffffff
或其他非零垃圾。
解决的办法是这样屏蔽它:
uint64_t val = ((hi & 0xffffffffULL) << 32) | (lo & 0xffffffffULL);
另外,如果我在作业过程中遮罩了,这似乎也可行:
uint64_t lo = ((buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]) & 0xffffffff;
uint64_t hi = ((buf[7] << 24) | (buf[6] << 16) | (buf[5] << 8) | buf[4]) & 0xffffffff;
我想知道为什么这是必要的。 我能想到的全部解释是,我的编译器直接在64位寄存器上进行lo
和hi
所有移位和合并,并且在这种情况下,我可能期望高阶32位有未定义的行为。
有人可以确认我的怀疑或以其他方式解释这里发生的事情,然后对我的两种解决方案中的哪一种(如果有)进行评论?
如果您尝试转换一个char
或未unsigned char
您将自己留在标准整数促销活动的摆布之下。 在尝试改变它们之前 ,最好自己铸造这些值。 如果这样做,您不必分开上下半部。
inline double ReadLittleEndianDouble( const unsigned char *buf )
{
uint64_t val = ((uint64_t)buf[7] << 56) | ((uint64_t)buf[6] << 48) | ((uint64_t)buf[5] << 40) | ((uint64_t)buf[4] << 32) |
((uint64_t)buf[3] << 24) | ((uint64_t)buf[2] << 16) | ((uint64_t)buf[1] << 8) | (uint64_t)buf[0];
return *(double*)&val;
}
仅当CPU是big-endian或缓冲区可能未针对CPU体系结构正确对齐时,所有这些操作才是必需的,否则可以大大简化此操作:
return *(double*)buf;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.