繁体   English   中英

uint64_t的未定义高阶,同时移位和屏蔽32位值

[英]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位变量lohi ,因此我可以合理地期望这些变量的高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位寄存器上进行lohi所有移位和合并,并且在这种情况下,我可能期望高阶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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM