Удивительное поведение strtoull ("- 1", NULL, 0) и других отрицательных значений - PullRequest
4 голосов
/ 07 марта 2019

strtoull("-1", NULL, 0) оценивается как 18446744073709551615, (0xFFFFFFFFFFFFFFFF aka ULLONG_MAX) в тестируемых мной системах (OS / X с Apple Libc, Linux с Glibc).

Поскольку strtoull являетсядолжен проверять значения вне диапазона возвращаемого типа, почему он не возвращает 0 для всех отрицательных значений?

РЕДАКТИРОВАТЬ: поведение вокруг -ULLONG_MAX также кажется несовместимым:

strtoul("-18446744073709551615", NULL, 0) -> 1, errno=0
strtoul("-18446744073709551616", NULL, 0) -> 18446744073709551615, errno=34

1 Ответ

9 голосов
/ 08 марта 2019

Преобладающая интерпретация стандарта раздела C (раздел 7.20.1.4 в C99, раздел 7.22.1.4 в C11, пункт 5 в обоих) заключается в том, что преобразование выполняется на первом шаге без учета знака минус, что дает результат без знака,Этот результат затем отрицается.На это указывает

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

в стандартетекст. Отрицательные значения беззнакового типа четко определены , поэтому общий результат представим, если первый шаг привел к представимому значению.Последующей ошибки из-за отрицания не возникает.

С другой стороны, если входная строка содержит такое большое число, что ее нельзя представить в виде значения unsigned long long int, первый шаг преобразованияне может привести к представимому значению, и применяется параграф 8:

Если правильное значение находится за пределами диапазона представимых значений, возвращается […] ULLONG_MAX […], и значениемакрос ERANGE хранится в errno.

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

...