标准 C 中无法便携检测字符串转浮点错误

No portable way to detect string-to-float conversion errors in standard C

我在标准 C 中发现了一个令人头疼的坑:无法便携地检测字符串转浮点(如 strtod)的转换错误。虽然 POSIX 规定溢出或下溢时必须设置 errno,但标准 C 的行为却依赖于 math_errhandling 宏。在 musl 等实现中,如果 math_errhandling 未启用 errno 支持,这些函数甚至不会报告错误。更糟糕的是,对于无效输入,不同 libc(如 glibc 和 musl)对 errno 的处理也不一致,导致简单的 errno 检查完全不可靠。要真正便携地检测错误,开发者必须同时检查 errno 和浮点异常标志,甚至手动解析字符串,这揭示了标准文档在错误处理描述上的模糊与缺陷。

这个情况完全是 Linux 手册页上未记录的,而且从我对标准的解读来看,它也不符合标准 C。
  1. Joker_vD

    令人惊讶的是,从 FORTRAN 到 Java/C# 等常用编程语言长期以来在函数调用中无法优雅地返回两个值,这导致人们发明了各种荒谬的 API/契约。

    [double x, errno_t errno] = strtod(s, nullptr);

    if (errno != 0) {

    // ...

    }

    [x, _] = strtod(s, nullptr); // 当你确定错误不可能发生,或者根本不在乎时

    相反,我们要么只能“检查返回值是否为 -1,如果是,再检查全局变量 errno”,要么就是“这个函数根本不可靠地报告错误,所以别喂给它格式错误的数据,我无所谓”。

  2. Panzerschrek

    C 语言的数字解析函数从根本上就是坏的,因为它们依赖于区域设置(locale)。当解析数字时假设它使用小数点,但在区域设置与开发者机器不同的系统上,小数点可能会突然变成逗号,这会导致许多 bug。因此,几乎总是应该避免使用它们,转而使用 std::from_chars(在新版 C++ 中可用)或其他第三方库。

  3. gucci-on-fleek

    > 这些函数的 Linux man pages 根本没有提到这一点

    > 让我觉得特别值得注意的是,man page 从未注明这是一个扩展([...])

    > 这在 Linux man page 上完全没有文档说明。

    根据我的经验,Linux man page 的维护者非常友好,所以向 [0] [1] 报告这个问题应该值得尝试。

    [0]: https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/...

    [1]: https://lore.kernel.org/linux-man/

  4. Kevin_Flynn

    > 标准 C 中没有可移植的方法来检测字符串转浮点错误

    标准 C 并不只有一个,有很多个。AI 说有 5 个。

    有 5 个主要的 ISO C 标准:C90、C99、C11、C17/C18 和 C23。C89 本质上与 C90 是同一个标准(只是 ANSI 名称不同),而 C95 是一个修订版而非独立的主要版本。最新的是 C23。

    正如你所知,POSIX 代表“可移植操作系统接口”。

    > posix 根本不在乎 math_errhandling;它总是要求实现者在发生溢出或下溢时设置 errno。

    所以,这个标榜“可移植”的接口规定,溢出/下溢错误必须总是被报告。

    问题似乎出在标题上,而不是规范本身。

  5. RossBencina

    微软的 strtod 实现长期以来都是坏的,我想大多数人现在应该都在使用 netlib 或一些更新的算法。

    https://www.exploringbinary.com/visual-c-plus-plus-strtod-st...

    https://lemire.me/blog/2026/02/01/converting-floats-to-strin...

同日更多故事

2026-10-12