[当我构建一个简单的程序让用户输入数字时(size_t num
),我不明白为什么输入负数导致数量巨大,而不是错误消息。
size_t num;
printf("enter num:");
scanf("%lu",&num);
printf("%lu",num);
%u
格式说明符实际上将接受带符号整数的字符串表示形式,并将结果转换为无符号整数。
fscanf
的第7.2.16.2p12节(并扩展为scanf
)对u
转换说明符说以下:从有符号到无符号的转换是通过将无符号类型可以保持+1的最大值逻辑地加到有符号类型的数值上,直到结果在无符号类型的范围内。请注意,无论相关整数类型的基本表示形式如何,都会发生这种情况。匹配一个可选的带符号十进制整数,其格式为与
strtoul
的主题序列相同base
参数的值为10的函数。的相应的参数应为指向无符号整数的指针。
因此,例如,假设size_t
是64位类型,它可以容纳的最大值是18446744073709551615615。因此,如果输入-1,则将18446744073709551616添加到-1,得到18446744073709551615这是结果。
此转换记录在第6.3.1.3节中:
1将整数类型的值转换为
_Bool
以外的其他整数类型时,如果该值可以用新的类型,它保持不变。2
否则,如果新类型是无符号的,则通过重复加或减一个大于新类型可以表示的最大值直到该值在新类型的范围内。
3否则,将对新类型进行签名,并且无法在其中表示值;结果是实现定义的或引发实现定义的信号。
u
转换的规范说:匹配一个可选的带符号十进制整数,其格式与strtoul
函数的主题序列的预期格式相同,且base
参数的值为10。相应的参数应为指向无符号整数的指针。
([l
修饰符进一步使它成为unsigned long
。]
因此,用%lu
扫描时允许有符号。根据第10段:
…输入项…被转换为适合转换说明符的类型。
到unsigned long
的转换以ULONG_MAX
+1为模,因此,较小的负值将转换为较大的正值。
size_t
是unsigned
。在数字的二进制表示中,第一位表示符号(对于signed int
),因此当计算机读取数字即认为它是size_t
时,它将不会将第一位解释为负号,而是将其解释为部分号码。由于它是第一位,即2的最高幂,因此得到的数字很大。您可以在此处阅读有关二进制表示的更多信息:https://en.wikipedia.org/wiki/Binary_number没有错误,因为计算机只是读取变量中在内存中指示的位,并且它代表有效的size_t
,因此计算机现在有办法知道这是错误的。