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
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_MAXis returned […], and the value of the macroERANGEis stored inerrno.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With