logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·02.11.26
← Back to news

C++ float-to-int conversion can be undefined behavior

Original article
kttnr.net|19 points|18 comments|by signa11|Jul 30, 2026

The Hidden Danger: Undefined Behavior in C++ Float-to-Int Conversions

In C++, the act of converting a floating-point number to an integer is not always safe. Specifically, it triggers undefined behavior (UB) if the value of the truncated float exceeds the capacity of the destination integer type.

The Illusion of Safety

Consider the following snippet. Despite the different syntaxes, all three lines perform the same operation:

void foo(float f) { 
    int i0 = f;                   // Implicit conversion
    int i1 = int(f);              // C-style cast
    int i2 = static_cast<int>(f); // Static cast
}

Surprisingly, this code is perfectly fine dangerous. Even when using strict compiler flags like -Wall and -Wextra, the compiler remains silent, offering no warnings that these operations could lead to UB.

What the Standard Says

According to the Floating-integral conversions section of the Cppreference implicit conversion guide, the rules are as follows:

  1. A floating-point prvalue can be converted to any integer type.
  2. The conversion process involves truncation: the fractional part is simply discarded. Mathematically, this is similar to: result=trunc(f)\text{result} = \text{trunc}(f)result=trunc(f)
  3. The Critical Warning: If the resulting value cannot be represented by the target type, the behavior is undefined. This holds true even for unsigned integers; the usual modulo arithmetic does not apply here.
Conversion TypeActionResult if Out-of-Range
float →\rightarrow→ intTruncate decimalsUndefined Behavior
double →\rightarrow→ uint32_tTruncate decimalsUndefined Behavior

Case Study: The GSL gsl::narrow Failure

The Guidelines Support Library (GSL), which implements the C++ Core Guidelines, provides a utility called gsl::narrow. This function is intended to be a "safe" narrowing cast that throws an exception if the value cannot fit in the target type T.

Internally, it performs a static_cast<T>(x). However, because it uses static_cast before checking the bounds, it triggers the UB described above. When this was brought to the attention of the maintainers, the response was dismissive:

"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)."

Hardware vs. Language Semantics

The argument that UB is "benign" stems from how specific hardware handles these errors. For instance, on x86 architectures, the CVTTSS2SI instruction is often used.

While the hardware might simply return INT_MIN (a placeholder), the C++ language views this as UB. As Ralf Jung explains in his insightful post, "What The Hardware Does" is not What Your Program Does, relying on hardware quirks is a mistake. Compilers optimize code based on the assumption that UB never occurs. If a compiler decides to optimize away a check because it assumes the value must fit, your program could crash or behave erratically after a simple compiler update.

UB Concept

How to Protect Your Code

To avoid these pitfalls, you can adopt a "saturating" approach (similar to how Rust handles these conversions) or use specialized tooling.

Prevention Checklist:

  • Avoid direct static_cast for potentially large floats.
  • Implement saturating casts (clamping the value to min or max of the type).
  • Use runtime sanitizers during testing.

To detect these issues automatically, compile your code with the following flag in Clang or GCC: -fsanitize=float-cast-overflow

Ultimately, the reasoning used by the GSL—that UB is acceptable if it "usually works"—has unfortunately leaked from the issue tracker directly into the production codebase, leaving a latent bug for users to find.