Daily Tech Briefing
AI 科技速览
每天 5 分钟内学习 AI。获取最新的人工智能新闻,理解其重要性,并学习如何将其应用于您的工作。
Hacker News · 2026/7/30 09:59:11
C++ float-to-int conversion can be undefined behavior
AI 中文解读
核心亮点:C++程序员常写的一个小操作,竟然藏着未定义行为的“大坑”,连微软官方库都中招了!
通俗解读:把小数转成整数,比如把3.7变成3,是编程里很常见的操作。但在C++语言里,如果这个数太大,超出了整数能装的范围,程序行为就不受法律保护了——可能崩溃,也可能给出乱七八糟的结果。更坑的是,编译器默认不报警,很多程序员根本不知道自己在走钢丝。就连微软发布的官方代码库都有这个问题,开发者还辩称“在自家硬件上没事”,但这显然不严谨。
实际影响:你可能不写代码,但这直接关系到软件质量。比如你用的App或游戏,底层C++代码如果埋着这种隐患,在某些特定输入下就可能闪退或算错数。虽然现在电脑处理器大多能“兜底”,但换台设备或升级编译器,结果可能就不一样了。好消息是,解决方式很简单:转换前先检查一下数值范围,或者用专门的检测工具扫一遍代码。这件事也给所有程序员提了个醒:别以为程序跑得动,就代表代码写对了。
C++ float-to-int conversion can be undefined behaviorConverting a float to an int in C++ is undefined behavior when the truncated float does not fit into the destination integer. C++ makes it easy to do this accidentally. Much code gets this wrong.void foo(float f) {
int i0 = f;
int i1 = int(f);
int i2 = static_cast<int>(f);
}
This code does not generate any warnings, not even with -Wall and -Wextra. -Wconversion only warns about the implicit conversion. Yet each of the three conversions is undefined behavior for some inputs.Cppreference's implicit conversion page, section Floating-integral conversions, states:A prvalue of floating-point type can be converted to a prvalue of any integer type. The fractional part is truncated, that is, the fractional part is discarded. If the value cannot fit into the destination type, the behavior is undefined (even when the destination type is unsigned, modulo arithmetic does not apply).I have seen this mistake many times in the wild. For example, in Microsoft's Guidelines Support Library, which supports the C++ Core Guidelines.GSL provides a function for safe narrowing conversions, gsl::narrow:gsl::narrow<T>(x) is a named cast that does a static_cast<T>(x) for narrowing conversions with no signedness promotions. If the argument x cannot be represented in the target type T, then the function throws.I was curious how they addressed float-to-int conversion. It turns out, contrary to the docs, that they do not address it. gsl::narrow is undefined behavior for some inputs. I pointed this out in a comment and was dismissed with the following reasoning:Regarding the use of UB internally: It's okay and if anyone is worried about it the use of UB is benign on the platforms we target (e.g., they don't involve hitting any hardware trap representations for these types).The undefined behavior is real, but with current processors and compilers, the program usually works anyway. Compilers tend to pick an instruction like x86's CVTTSS2SI, which maps every unrepresentable input to the same placeholder integer INT_MIN. AArch64 has FCVTZS, which saturates and maps NaN to zero.Your program not crashing can make the problem seem benign. It is not. Different results on different hardware are problematic. More importantly, any undefined behavior that executes is problematic. Ralf Jung explains this well in his post "What The Hardware Does" is not What Your Program Does. (I recommend his blog.) Your code could suddenly stop working when the compiler happens to apply a different transformation.The correct fix is to bounds check before casting. I turned this into a proof of concept library based on Rust's saturating approach.You can also detect the undefined behavior with Clang's and GCC's Undefined Behavior Sanitizer, see -fsanitize=float-cast-overflow. I recommend testing all C++ code with UBSan anyway.The faulty GSL reasoning has made it from the issue comment into the code. The problem has not been fixed.created 2026-07-29, updated 2026-07-30root · blog
分享
阅读原文 ↗