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

chq*_*lie 4 c language-lawyer strtoull

strtoull("-1", NULL, 0)在我测试的系统(带有Apple Libc的OS / X,带有Glibc的Linux)上的计算结果为18446744073709551615,(0xFFFFFFFFFFFFFFFF又名ULLONG_MAX)。

由于strtoull应该检查返回值范围之外的值,为什么它不0为所有负值返回?

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

strtoul("-18446744073709551615", NULL, 0) -> 1, errno=0
strtoul("-18446744073709551616", NULL, 0) -> 18446744073709551615, errno=34
Run Code Online (Sandbox Code Playgroud)

Flo*_*mer 9

C节标准(C99中的7.20.1.4节,C11中的7.22.1.4节,两者中的第5段)的主流解释是,转换是在第一步中执行的,而不考虑负号,产生无符号结果。然后,该结果被否定。这是由建议

如果主题序列以减号开头,则转换结果取反(返回类型)。

在标准文字中。 无符号类型的取反值定义明确,因此,如果第一步得到可表示的值,则总体结果可表示。由于没有,因此没有后续错误。

另一方面,如果输入字符串包含的数字太大,以致无法将其表示为unsigned long long int值,则转换的第一步将不会产生可表示的值,并且第8段适用:

如果正确值超出可表示值的范围,ULLONG_MAX则返回[…] […],并将宏的值ERANGE存储在中errno

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