【问题标题】:scanf %u negative number?scanf %u 负数?
【发布时间】:2016-12-05 16:19:36
【问题描述】:

我试过scanf("%u",&number) 并且我输入了负数问题是当我printf("%d",number) 得到负数时。我认为这会阻止我阅读负数。 scanf("%d",&number)scanf("%u",&number) 真的是一回事吗? 还是只是为了便于阅读。

我是在做一些所谓的未定义行为吗?

编辑:

来自Wikipedia 我读到这个:

%u :扫描十进制无符号整数(请注意,在 C99 标准中 输入值减号是可选的,所以如果读取了减号,则没有 将出现错误,结果将是 a 的二进制补码 负数,可能是一个非常大的值。

阅读 SO 答案及以上内容有点令人困惑。谁能说的更清楚一点?

【问题讨论】:

标签: c printf scanf unsigned format-specifiers


【解决方案1】:

是的,无论哪种方式,它都是未定义的行为。

考虑到变量numberunsigned 类型,printf() 中的%d 需要signed int 类型的参数,传递unsigned 类型是UB。

OTOH,如果number 是签名类型,则使用%u 进行扫描首先是UB。

如你所料

[...] 阻止我读取负数

格式说明符用于防止不正确的输入。如果格式说明符与提供的参数不匹配,则调用undefined behavior

引用 C11,附件 J.2,调用 UB 的场景,

不能通过格式化输入函数之一的转换结果 在相应的对象中表示,或者接收对象没有 合适的类型

【讨论】:

  • printf("%u",-1)也是UB吗?
  • @rondino 从技术上讲是这样。 see this
  • @rondino:是的,printf("%u", -1) 具有未定义的行为。 -1int 类型,%u 需要 unsigned int 类型的参数。对应的有符号和无符号类型在某些情况下可以互换,但适用于在这两种类型中都可表示的值。
【解决方案2】:

正如 Sourav Ghosh 详细解释的那样,使用与传递的实际类型不一致的格式是一个潜在问题。然而对于这种特殊情况,在当前的 PC 架构上,这并不是真正的问题,因为 intunsigned int 都没有陷阱表示。

您可以使用scanf("%u", &number); 扫描负数。它将在目标类型中被取反,即unsigned int,具有与带符号int 中的负数相同的按位表示,用于二进制补码表示,这在当前架构上几乎是通用的。

scanf 通过匹配一个可选带符号的十进制整数来转换%u,其格式与strtoul 函数的主题序列的预期相同,其值为10 为基本参数。对应的参数应该是一个指向无符号整数的指针。

strtolstrtollstrtoulstrtoull 函数将 nptr 指向的字符串的初始部分转换为 long intlong long intunsigned long int 和 @987654338 @ 表示,分别。首先,他们将输入字符串分解为三个部分:一个初始的,可能为空的空白字符序列(由isspace 函数指定),一个类似于整数的主题序列,该整数以由 base 的值确定的某个基数表示,以及一个或多个无法识别的字符的最终字符串,包括输入字符串的终止空字符。然后,他们尝试将主题序列转换为整数,并返回结果。

如果 base 的值介于 2 和 36(含)之间,则主题序列的预期形式是表示整数的字母和数字序列,其基数由 base 指定,前面可选加号或减号,但不包括整数后缀。

...如果主题序列具有预期的形式并且碱基的值在 2 到 36 之间,则将其用作转换的碱基,为每个字母赋予其值,如上所示。如果主题序列以减号开头,则转换产生的值被取反(在返回类型中)。

如果number 的类型是unsigned int,则定义行为并使用无符号否定语义解析负值并将其存储到number。使用printf("%d", number); 打印此值至多是定义的实现,但同样,在当前的PC 架构上,将打印最初由scanf("%u", &number); 解析的负数

结论:虽然看起来无害,但将intunsigned int互换使用,在printfscanf中使用错误的格式是非常草率的。事实上,在表达式中混合有符号和无符号类型,尤其是。 in 比较是非常容易出错的,因为这种结构的 C 语义有时是违反直觉的。

【讨论】:

  • "它将在目标类型中取反,命名为 unsigned,与 signed int 中的负数具有相同的按位表示。" -- 这是真的仅适用于 2 的补码表示(这几乎是通用的,但不能保证)。
  • @KeithThompson:正确。我更新了答案。我迫不及待地想看到这些过时的可能性从 C 标准的未来版本中删除。
猜你喜欢
  • 1970-01-01
  • 2021-04-08
  • 2013-11-25
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多