Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Surprising behavior of strtoull("-1", NULL, 0) and other negative values

strtoull("-1", NULL, 0) evaluates to 18446744073709551615, (0xFFFFFFFFFFFFFFFF aka ULLONG_MAX) on the systems I tested (OS/X with Apple Libc, Linux with Glibc).

Since strtoull is supposed to check for values out of the range of the return type, why does it not return 0 for all negative values?

EDIT: the behavior around -ULLONG_MAX seems inconsistent too:

strtoul("-18446744073709551615", NULL, 0) -> 1, errno=0
strtoul("-18446744073709551616", NULL, 0) -> 18446744073709551615, errno=34
like image 440
chqrlie Avatar asked Dec 24 '22 00:12

chqrlie


1 Answers

The prevailing interpretation of section C standard (section 7.20.1.4 in C99, section 7.22.1.4 in C11, paragraph 5 in both) is that the conversion is performed in a first step, disregarding the minus sign, producing an unsigned result. This result is then negated. This is suggested by

If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type).

in the standard text. Negating values of unsigned type is well-defined, so the overall result is representable if the first step resulted in a representable value. There is no subsequent error due to the negation.

On the other hand, if the input string contains a number that is so large that it cannot be represented as an unsigned long long int value, the first step of the conversion cannot result in a representable value, and paragraph 8 applies:

If the correct value is outside the range of representable values, […] ULLONG_MAX is returned […], and the value of the macro ERANGE is stored in errno.

Again, virtually all implementers interpret the standard in such a way that the the representable value check only applies to the first conversion step, from an arbitrary-precision nonnegative integer in the input string to the unsigned type.

like image 125
Florian Weimer Avatar answered Dec 31 '22 01:12

Florian Weimer