В стандартном C нет переносимого способа обнаружить ошибки преобразования строки в число с плавающей запятой
No portable way to detect string-to-float conversion errors in standard C
Автор разбирает, почему в стандартном C невозможно надёжно проверить ошибки преобразования строки в число с плавающей запятой. Функции strtod и подобные зависят от math_errhandling: если поддержка errno не заявлена, ошибки переполнения и антипереполнения могут не устанавливать errno. POSIX требует всегда устанавливать errno, что противоречит стандарту C. На практике glibc и musl ведут себя по-разному при неверном вводе, а man-страницы умалчивают об этом.
на glibc это печатает 0, потому что strtod в glibc никогда не устанавливает errno в EINVAL. musl, напротив, устанавливает errno в EINVAL, так что печатается «22».
- 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 принципиально сломаны, поскольку зависят от локали. Есть куча багов, когда кто-то разбирает число, предполагая, что в нём десятичная точка, но потом на системах с локалью, отличной от той, что была на машине разработчика, внезапно оказывается запятая вместо точки. Так что их почти всегда следует избегать и использовать std::from_chars (доступна в новых версиях C++) или какую-нибудь другую стороннюю библиотеку.
- gucci-on-fleek
> в man-страницах Linux для этих функций об этом вообще ничего не сказано
> тот факт, что в man-странице никогда не отмечается, что это расширение ([…]), для меня действительно примечателен.
> это совершенно не задокументировано на man-странице Linux.
Сопровождающие man-страниц Linux, по моему опыту, очень дружелюбны, так что, вероятно, стоит сообщить им об этом [0] [1].
[0]: https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/...
- kazinator
Не забывайте про локаль! Если вы находитесь в неправильной локали, strtod("3,4", ...) может вернуть 3.4 и т.д.
- chasil
IEEE-754 — суровая госпожа.