【问题标题】:Why does a negative number converted to size_t become a huge number in C?为什么转换为 size_t 的负数在 C 中会变成一个巨大的数字?
【发布时间】:2020-04-15 11:38:20
【问题描述】:

当我构建一个让用户输入数字的简单程序时 (size_t num),我不明白为什么要输入负数 结果是一个巨大的数字而不是错误消息。

size_t num;
printf("enter num:");
scanf("%lu",&num);
printf("%lu",num);

【问题讨论】:

  • 作为旁注:size_t 不用于存储和表示负值。如果您也想表示负值,请在对scanf()printf() 的调用中使用ssize_t%zd 转换说明符。

标签: c unsigned size-t


【解决方案1】:

%u 格式说明符实际上将接受带符号整数的字符串表示形式,并将结果转换为无符号整数。

C standard 的第 7.21.6.2p12 节关于 fscanf 函数(以及通过扩展,scanf)对u 转换说明符进行了以下说明:

匹配可选带符号的十进制整数,其格式为 与strtoul 的主题序列的预期相同 base 参数的值为 10 的函数。这 对应的参数应该是一个指向无符号整数的指针。

从有符号到无符号的转换是通过逻辑地将无符号类型可以保持的最大值+1加到有符号类型的数值上,直到结果在无符号类型的范围内。请注意,无论相关整数类型的底层表示如何,都会发生这种情况。

例如,假设size_t是64位类型,它可以容纳的最大值是18446744073709551615。所以如果你输入-1,那么18446744073709551616被加到-1上,结果是18446744073709551615。

p>

此转换记录在第 6.3.1.3 节中:

1 当一个整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新的表示 类型,它是不变的。

2 否则,如果新类型是无符号的,则通过重复加减一的方式转换值 新类型可以表示的最大值 直到值在新类型的范围内。

3 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的 或引发实现定义的信号。

【讨论】:

    【解决方案2】:

    C 2018 7.21.6.2 12 中 u 转换的规范说:

    匹配一个可选带符号的十进制整数,其格式与strtoul 函数的主题序列的预期格式相同,base 参数的值为 10。对应的参数应该是一个指向无符号整数的指针。

    l 修饰符进一步使其成为unsigned long。)

    因此,当使用%lu 扫描时,允许使用符号。根据第 10 段:

    …输入项…被转换为适合转换说明符的类型。

    转换为unsigned long wrap modulo ULONG_MAX+1,因此小的负值被转换为大的正值。

    顺便说一句,要将数字扫描成size_t,您应该使用%zuz 修饰符专门用于 size_t

    【讨论】:

      【解决方案3】:

      size_tunsigned。在数字的二进制表示中,第一位表示符号(对于signed int),因此当计算机读取数字时认为它是size_t,它不会将第一位解释为负号,而是解释为数的一部分。因为它是第一位,即两个的最高幂,所以你得到一个很大的数。您可以在此处阅读有关二进制表示的更多信息:https://en.wikipedia.org/wiki/Binary_number

      没有错误,因为计算机只是读取内存中变量指示的位,这表示一个有效的size_t,所以现在计算机有办法知道这是错误的。

      【讨论】:

      • 显然是的,但这并不能解释为什么scanf() 不会失败。 "%lu""%ld" 不同,那么,为什么scanf() 接受负数(并返回1,并将值存储在num 中)? (顺便说一句,signed/unsigned int"%d"/"%u" 的问题是一样的)
      • size_t 是无符号类型。不一定是unsigned int
      • @prog-fh scanf() 无法判断格式字符串实际上与参数列表不匹配,这是开发人员的工作
      • @FelixG 不!这里scanf() 知道格式字符串 输入。这不是一个糟糕的演员阵容问题。
      • @prog-fh scanf() 从不知道除了格式字符串中指定的参数之外的任何参数。编译器可以进行交叉检查(如果它是一个不错的编译器并且启用了相应的警告),但 scanf() 函数本身不能。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 2010-12-02
      • 1970-01-01
      • 2020-08-19
      • 1970-01-01
      相关资源
      最近更新 更多