标准 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。
HN 评论区
56- Joker_vD
令人惊讶的是,从 FORTRAN 到 Java/C# 等常用编程语言长期以来在函数调用中无法优雅地返回两个值,这导致人们发明了各种荒谬的 API/契约。
[double x, errno_t errno] = strtod(s, nullptr);
if (errno != 0) {
// ...
}
[x, _] = strtod(s, nullptr); // 当你确定错误不可能发生,或者根本不在乎时
相反,我们要么只能“检查返回值是否为 -1,如果是,再检查全局变量 errno”,要么就是“这个函数根本不可靠地报告错误,所以别喂给它格式错误的数据,我无所谓”。
- Panzerschrek
C 语言的数字解析函数从根本上就是坏的,因为它们依赖于区域设置(locale)。当解析数字时假设它使用小数点,但在区域设置与开发者机器不同的系统上,小数点可能会突然变成逗号,这会导致许多 bug。因此,几乎总是应该避免使用它们,转而使用 std::from_chars(在新版 C++ 中可用)或其他第三方库。
- 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/...
- 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。
所以,这个标榜“可移植”的接口规定,溢出/下溢错误必须总是被报告。
问题似乎出在标题上,而不是规范本身。
- RossBencina
微软的 strtod 实现长期以来都是坏的,我想大多数人现在应该都在使用 netlib 或一些更新的算法。
https://www.exploringbinary.com/visual-c-plus-plus-strtod-st...
https://lemire.me/blog/2026/02/01/converting-floats-to-strin...