← На главную

C-функции atol, strtoul и sscanf сломаны — фикс от Alejandro Colomar

20.05.2026 10:28 · hackernews

В стандартной библиотеке C есть три функции для парсинга строк в числа: atol(), strtol()/strtoul() и sscanf(). Они все сломаны. atol() вообще бесполезна: на входе «123timmy» она вернёт 123, на переполнении — LONG_MAX, а на пустой строке — 0. И никак не узнать, что пошло не так. В стандарте поведение при переполнении — неопределённое, то есть на бумаге atol() может хоть диск отформатировать. На практике так не делают, но полагаться на это нельзя.

strtol() можно использовать правильно — если вручную проверять errno, пустую строку и остаток строки *endp. Но только для знаковых типов. strtoul() же сломана принципиально. Она принимает минус, преобразует его в беззнаковое значение по правилам модульной арифметики. То есть -1 превращается в 2^64-1, -2^63 — в 2^63, и так далее. Отличить «реальное» значение 18446744073709551615 от результата парсинга -1 невозможно. Строка из пробелов ловится как ошибка, но это, видимо, случайность.

sscanf() с форматом %lu тоже не годится. Отрицательные числа обрабатываются так же, как strtoul(), а переполнение выдаёт ULONG_MAX без возможности понять, что это ошибка, а не корректный ввод.

Автор удивляется: почему в 2023 году нет нормального парсера беззнаковых целых в стандартной библиотеке C? В Python int("123") делает всё правильно (но только для знаковых). C++ std::stoul() тоже сломана — те же проблемы с отрицательными. std::from_chars() из C++17, судя по обновлению в статье, работает корректно: не позволяет знака минус для беззнаковых типов, возвращает ошибку и не оставляет мусора.

Alejandro Colomar подсказал обходной путь для C: перед вызовом strtoul() проверить строку через strtol(). Если strtol() даёт отрицательное значение — возвращать ошибку. Дальше можно спокойно вызывать strtoul(). Это простое решение, которое действительно работает для беззнаковых чисел.

Читать оригинал →