Конфликтует ли реализация strtoul в glibc со стандартом C11?

Ниже приводится описание функции strtoul в stdlib.h, реализованной glibc:

Функция: unsigned long int strtoul (const char * retrict string, char ** restrict tailptr, int base) Предварительно: | Региональный стандарт MT-Safe | AS-Safe | AC-Safe | См. Концепции безопасности POSIX.

Функция strtoul («строка-в-беззнаковый-длинный») похожа на strtol, за исключением того, что она преобразуется в значение типа unsigned long int. Синтаксис такой же, как описано выше для strtol. Значение, возвращаемое при переполнении, - ULONG_MAX (см. «Диапазон типов»).

Если строка представляет собой отрицательное число, strtoul действует так же, как strtol, но преобразует результат в целое число без знака. Это означает, например, что strtoul на «-1» возвращает ULONG_MAX, а ввод более отрицательный, чем возвращает LONG_MIN (ULONG_MAX + 1) / 2.

strtoul устанавливает для errno значение EINVAL, если база вне допустимого диапазона, или ERANGE при переполнении.

Это означает, что, например, "-2" будет преобразовано в ULONG_MAX - 1. Но стандарт C11 [7.22.1.4-8] говорит:

Функции strtol, strtoll, strtoul и strtoull возвращают преобразованное значение, если оно есть. Если преобразование не может быть выполнено, возвращается ноль. Если правильное значение выходит за пределы диапазона представимых значений, возвращается LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX или ULLONG_MAX (в соответствии с типом возвращаемого значения и знаком значения, если таковые имеются), и значение макроса ERANGE сохраняется в errno.

Так, например, по стандарту "-2" должен быть преобразован в ULONG_MAX. Это конфликт?


person xskxzr    schedule 01.10.2015    source источник
comment
Обратите внимание, что glibc следует posix в большей степени, чем стандарту C. Однако C11 7.22.1.4.5, похоже, также имеет дело со знаком -, хотя мне совершенно неясно, должно ли это отрицание иметь место до того, как произойдет фрагмент из 7.22.1.4-8, который вы цитируете.   -  person nos    schedule 01.10.2015
comment
@nos, спасибо, но как я отвечаю chux, даже если это происходит после преобразования переполнения, конфликт все равно существует.   -  person xskxzr    schedule 02.10.2015


Ответы (2)


Вероятно, это еще один случай glibc реализации функции до того, как произошла стандартизация.

Да, это конфликтует.

Однако я считаю результат glibc более полезным. Если вам нужно полное соответствие, вы можете обернуть функцию для выполнения преобразования.

person wallyk    schedule 01.10.2015
comment
Спасибо. Я согласен с тобой. Вы знаете, где сообщить об этой ошибке? - person xskxzr; 02.10.2015
comment
@Shenke: Зависит. Если ошибка в стандарте, то непонятно, куда о ней сообщать. Если вы думаете, что в glibc есть ошибка, то нужно найти что-то убедительное, чтобы заменить их стандарт новым стандартом. Изменения могут нарушить многие существующие способы использования. - person wallyk; 02.10.2015
comment
В примере -2 нет конфликта, glibc правильно следует стандарту. (Вопрос неверно интерпретирует стандарт). Значения более отрицательные, чем LONG_MIN, были бы другим случаем, хотя, прежде чем выносить суждение, было бы хорошо проверить фактическое поведение функции glibc, а не доверять опубликованной документации (что не имеет большого смысла) - person M.M; 08.03.2019

Никакого конфликта.

Если субъектная последовательность начинается со знака минус, значение, полученное в результате преобразования, инвертируется (в возвращаемом типе). C11dr §7.22.1.4 5

unsigned отрицание хорошо определено.

Вычисление с участием беззнаковых операндов никогда не может переполниться, потому что результат, который не может быть представлен результирующим целочисленным типом без знака, уменьшается по модулю числа, которое на единицу больше наибольшего значения, которое может быть представлено результирующим типом. §6.2.5 9

По стандарту "-2" должно быть преобразовано в ULONG_MAX - 2.

Так что, возможно, текст «Function: unsigned long ... overflow» каким-то образом конфликтует со спецификацией C (в частности, «ввод более отрицательный, чем LONG_MIN возвращает (ULONG_MAX + 1) / 2)», но функциональность strtoul() верна.

person chux - Reinstate Monica    schedule 01.10.2015
comment
Спасибо. Как говорит @nos, я не знаю, происходит ли отрицание до или после преобразования переполнения, которое я цитирую. Но даже если это происходит после преобразования переполнения, как вы говорите, все еще может существовать конфликт на входе, более отрицательном, чем LONG_MIN, например, - ULONG_MAX (реализация вернет (ULONG_MAX + 1) / 2, в то время как он должен быть 1 по стандарту). - person xskxzr; 02.10.2015
comment
@Shenke Я только что тестировал как на 32-битном, так и на 64-битном хосте, он вернул 1. - person nos; 02.10.2015
comment
@nos Я запуталась. Похоже, что реальная реализация glibc не совсем такая, как то, что она документирует. Документ слишком старый? Я нахожу его на этом веб-сайте: gnu.org/software/libc/manual /html_mono/libc.html - person xskxzr; 02.10.2015
comment
@Shenke Согласно спецификации C 7.22.1.4-8, мягко подразумевает (обратите внимание на порядок имен функций и ограничений диапазона) strtoul(), использует диапазон [0...ULONG_MAX], а не [LONG_MIN ...ULONG_MAX]. Отрицание происходит после значения, полученного в результате преобразования согласно C11dr §7.22.1.4 5. - person chux - Reinstate Monica; 02.10.2015