9,999,999,999(十个9s)太大了,无法放入您的int 数据类型。如果你算出它和1,410,065,407 之间的区别,你会发现它是 2 的精确幂(准确地说是 233),这意味着它在你扫描它时会缠绕。
我所说的“环绕”是指整数的属性,即简单地环绕在它们的最大值处以成为意想不到的东西。
例如,可以保存值 0..255 的 8 位无符号整数,当您将 1 添加到保存 255 的变量时,将变为零(有符号值倾向于从最大的正值回绕到最小的正值负值,在这种情况下,最小意味着离零最远)。
假设您正在读取一个十进制数,其中类型的范围为0..255,该数字的字符串表示为456。下面的“代码”大概是它的工作原理:
def scanNum(s):
result = 0
for each character c in s:
result = result * 10 + value(c)
return result
- 在处理
4 字符时,result 乘以十,0 * 10 = 0,然后再加四,得到4。
- 处理
5 字符时,result 乘以十,4 * 10 = 40,然后再加五,得到45。
- 在处理
6 字符时,result 乘以十,45 * 10 = 450 但是, 因为你只能表示0..255,它会回绕,给你450 - 256 = 194。然后你加六,得到200。
您可以在那里看到,您想要的和您得到的之间的差异也与范围非常相关:456 - 200 = 256。
如果您尝试使用 9 9s(或 999,999,999,请记住 32 位二进制补码可表示的最大数在 2,147,483,647 处更大),或使用能够容纳更大数字的数据类型,您可能会发现它没问题:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
long long n;
printf("Enter the number to be checked\n");
scanf("%lld",&n);
printf("%lld\n", n);
return 0;
}
根据标准,我最初认为这是错误的,因为根据C11 7.21.6.2 The fscanf function /12,它遵循strtol 函数:
d 匹配一个可选带符号的十进制整数,其格式与 strtol 函数的主题序列的预期格式相同,base 参数的值为 10。对应的参数应该是一个指向有符号整数的指针。
和strtol 函数,C11 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions /8 状态:
如果正确值超出可表示值的范围,则返回 LONG_MIN、LONG_MAX、LLONG_MIN、LLONG_MAX、ULONG_MAX 或 ULLONG_MAX(根据返回类型和值的符号,如果有)。
但实际上,只有 格式 遵循该功能。 fscanf 及其兄弟的 结果 由 C11 7.21.6.2 The fscanf function /10 控制:
如果这个对象没有合适的类型,或者如果转换的结果不能在对象中表示,行为是未定义的。
因此,如果超出范围,您返回的数字可以是任何值,事实上,鉴于未定义行为的结果没有限制,它可以做任何事情,而不仅仅是返回一个狡猾的结果,包括格式化你的磁盘和将本地时空坍缩成一个裸奇点:-)
在这种情况下,它似乎只是将值包装为扫描过程的一部分,这是代码要做的最简单的事情。