如何在 C++ 中获得没有 UB 的浮点位表示?

Posted

技术标签:

【中文标题】如何在 C++ 中获得没有 UB 的浮点位表示?【英文标题】:How to get float bit representation without UB in C++? 【发布时间】:2020-02-10 12:31:33 【问题描述】:

据我所知,所有这样做的“传统”方式,即指针的reinterpret_cast 和带有intfloat 字段的union 都是UB,因为它违反了严格的别名(in C++, not in C) . 那么,如何在没有未定义行为的情况下正确地做到这一点?

我可以对char * 执行reinterpret_cast 并将其存储到uint32_t 吗?或者std::launder 会有所帮助吗?

【问题讨论】:

如果您只想“获取”位表示,您可以简单地将指向float 的指针转换为const unsigned char * 并使用生成的指针来检查对象的字节。但是你为什么提到“memcpy that to float”?复制到float 没有得到位表示;它正在改变位。你真正想做什么? 在 cppcon 2019 上有一个关于这个问题的 1h talk。您可能对此感兴趣。 @EricPostpischil 是的,对不起,我的意思是'memcpy to uint32_t`,我会编辑问题。 memcpy that to uint32_t - 你为什么要这样做来打印位?您可以从char 打印它们。 @KamilCuk 好吧,我想让它们作为一个连续的东西,以获得有效和指数;从 char 数组中获取它们会有点乏味。 【参考方案1】:

正如Jason Turner 所指出的,标准的做法是使用memcpy

float f = 1.0;
std::byte c[sizeof(f)];
memcpy(c, &f, sizeof(f));

您可能认为您不想复制任何内容,只想查看位/字节。好吧,编译器很聪明,他们实际上会优化它,正如 Jason 所证明的那样,所以不要担心,使用 memcpy 处理这种事情,永远不要使用 reinterpret_cast

【讨论】:

C++20 std::bit_cast() 值得一提。 没错!这将是执行此操作的标准方式。 我不怕复制,我怕未定义的行为 :) 谢谢!那么std::launder呢? @Amomum std::laundrs 返回类型与其参数类型相同。所以从floatunsigned 的转换是不可能的。 @Timo std::launder(reinterpret_cast<uint32_t *>(f)) 怎么样?

以上是关于如何在 C++ 中获得没有 UB 的浮点位表示?的主要内容,如果未能解决你的问题,请参考以下文章

Lua和C++中的浮点数的比较

Lua和C++中的浮点数的比较

如何使用字典在网格中获得点位置?

如何在 C++ 中快速解析空格分隔的浮点数?

查找具有相同内部表示的浮点数/双精度数的最小值/最大值

c++中如何输出保留三位小数的浮点数