strtoull("-1", NULL, 0) 和其他负值的惊人行为

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

strtoull("-1", NULL, 0) 在我测试的系统(OS/X with Apple Libc,Linux 与 Glibc).

既然 strtoull 应该检查超出 return 类型范围的值,为什么它不 return 0 检查所有负值?

编辑: -ULLONG_MAX 周围的行为似乎也不一致:

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

C 部分标准(C99 中的第 7.20.1.4 节,C11 中的第 7.22.1.4 节,两者的第 5 段)的普遍解释是转换是在第一步中执行的,忽略减号,产生一个未签名的结果。这个结果然后被否定。

建议

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

在标准文本中。 Negating values of unsigned type is well-defined,因此如果第一步产生可表示的值,则总体结果是可表示的。由于取反没有后续错误。

另一方面,如果输入字符串包含的数字太大以至于无法表示为 unsigned long long int 值,则转换的第一步无法生成可表示的值,并且段落8 个适用:

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.

同样,几乎所有实施者都以这样一种方式解释标准,即可表示值检查仅适用于第一个转换步骤,从输入字符串中的任意精度非负整数到无符号类型。