8字节值强转double打印错误,使用memcpy却正常,是什么原因?
差异原因
C/C++中数值强制类型转换和二进制内存拷贝是完全不同的操作,二者逻辑没有任何关联:
- 你写的
(double)raw_packet属于数值转换:编译器会把unsigned long long类型存储的整数4750079349732465269作为真实数值,按照整数转浮点数的规则,把这个整数值转换成最接近的双精度浮点数输出,自然不符合预期。 - 你使用的
memcpy属于二进制拷贝:不会修改8字节的任何二进制位,只是把这8个字节的原始内容,交给double类型的变量按照IEEE754双精度浮点数编码规则去解析,得到的就是传感器发送的正确时间戳。
你给出的示例二进制值0x75dab86700aceb41本身就对应两个完全不同的含义:作为无符号64位整数的数值就是4750079349732465269,作为IEEE754双精度浮点数的编码值就是3714057021.7766671,和你代码输出完全吻合。
同类问题修复方案
后续处理传感器原始报文、需要把二进制序列按照指定类型解析的场景,不要使用强制类型转换,优先选择以下两种安全方案:
- 沿用你现有的
memcpy方案,将原始二进制内容直接拷贝到对应类型的变量中,该方案跨平台兼容性最好,不存在未定义行为 - 如果使用C++20及以上标准,可以用
std::bit_cast<double>(raw_packet)完成同样的转换,代码语义更清晰,效果和memcpy完全一致
注意:不要使用*((double*)&raw_packet)这类指针强转写法,该写法违反C/C++严格别名规则,属于未定义行为,编译器开启优化后可能出现不可预期的错误。
内容的提问来源于stack exchange,提问作者usinjin
相关产品推荐
相关产品推荐

