是否应该通过std :: cin将负数读入未签名失败(gcc,clang不同意)? [英] Should reading negative into unsigned fail via std::cin (gcc, clang disagree)?

查看:189
本文介绍了是否应该通过std :: cin将负数读入未签名失败(gcc,clang不同意)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,

#include <iostream>

int main() {
  unsigned n{};
  std::cin >> n;
  std::cout << n << ' ' << (bool)std::cin << std::endl;
}

当输入-1时, c 6.0.0 输出0 0 gcc 7.2.0 输出4294967295 1.我想知道谁是正确的.还是两者都是正确的,对于标准没有指定这一点?失败是指(bool)std::cin被评估为假.铛6.0.0也无法输入-0.

When input -1, clang 6.0.0 outputs 0 0 while gcc 7.2.0 outputs 4294967295 1. I'm wondering who is correct. Or maybe both are correct for the standard does not specify this? By fail, I take to mean (bool)std::cin be evaluated false. clang 6.0.0 fails input -0 too.

从Clang 9.0.0和GCC 9.2.0开始,对于Clang,使用libstdc ++或libc ++的两个编译器都同意上述程序的结果,而与C ++版本无关(> = C ++ 11 )使用,然后打印

As of Clang 9.0.0 and GCC 9.2.0, both compilers, using either libstdc++ or libc++ in the case of Clang, agree on the result of the program above, independent of the C++ version (>= C++11) used, and print

4294967295 1

即他们将值设置为ULLONG_MAX,而不在流上设置故障位.

i.e. they set the value to ULLONG_MAX and do not set the failbit on the stream.

推荐答案

我认为在C ++ 17 1 中两者都是错误的,预期输出应为:

I think that both are wrong in C++171 and that the expected output should be:

4294967295 0

虽然返回值对于两个编译器的最新版本都是正确的,但我认为应该设置ios_­base​::​failbit,但是我也认为对于要转换的字段的概念感到困惑 >可能解释当前行为的标准.

While the returned value is correct for the latest versions of both compilers, I think that the ios_­base​::​failbit should be set, but I also think there is a confusion about the notion of field to be converted in the standard which may account for the current behaviors.

标准说— [facet.num.get.virtuals#3.3] :

The standard says — [facet.num.get.virtuals#3.3]:

第2阶段(该字段)中累积的字符序列通过标头<cstdlib>中声明的函数之一的规则转换为数字值:

The sequence of chars accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header <cstdlib>:

  • 对于有符号整数值,请使用函数strtoll.

对于无符号整数值,请使用函数strtoull.

For an unsigned integer value, the function strtoull.

对于浮点值,请使用函数strtold.

For a floating-point value, the function strtold.

因此,我们回退到 std::strtoull ,它必须返回 2 ULLONG_MAX且在这种情况下未设置errno(这两个编译器都这样做).

So we fall back to std::strtoull, which must return2 ULLONG_MAX and not set errno in this case (which is what both compilers do).

但在同一区块中(强调是我的):

But in the same block (emphasis is mine):

要存储的数值可以是以下之一:

The numeric value to be stored can be one of:

  • 零,如果转换函数不能转换整个字段.

  • zero, if the conversion function does not convert the entire field.

最正(或负)可表示的值,如果要转换为有符号整数类型的字段表示正(或负)值太大而无法在.

the most positive (or negative) representable value, if the field to be converted to a signed integer type represents a value too large positive (or negative) to be represented in val.

最正的可表示值,如果要转换为无符号整数类型的字段表示不能用val表示的值.

the most positive representable value, if the field to be converted to an unsigned integer type represents a value that cannot be represented in val.

已转换的值,否则.

结果数字值存储在val中.如果转换函数不能转换整个字段,或者该字段表示的值超出可表示值的范围,则将ios_­base​::​failbit分配给err.

The resultant numeric value is stored in val. If the conversion function does not convert the entire field, or if the field represents a value outside the range of representable values, ios_­base​::​failbit is assigned to err.

请注意,所有这些都是关于 要转换的字段" 的,而不是std::strtoull返回的实际值.这里的字段实际上是字符'-', '1'的扩展序列.

Notice that all these talks about the "field to be converted" and not the actual value returned by std::strtoull. The field here is actually the widened sequence of character '-', '1'.

由于该字段表示的值(-1)不能用unsigned表示,因此返回的值应为UINT_MAX,而故障位应设置为std::cin.

Since the field represents a value (-1) that cannot be represented by an unsigned, the returned value should be UINT_MAX and the failbit should be set on std::cin.

1 clang实际上是在C ++ 17之前,因为上面引用中的第三个项目符号是:

1clang was actually right prior to C++17 because the third bullet in the above quote was:

-最负的可表示值,对于无符号整数类型为零,如果该字段表示的负值太大而无法在val中表示. ios_base::failbit被分配给err.

- the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in val. ios_base::failbit is assigned to err.

2 std::strtoull 返回ULLONG_MAX是因为(感谢@NathanOliver)— C/7.22.1.4.5:

2 std::strtoull returns ULLONG_MAX because (thanks @NathanOliver) — C/7.22.1.4.5:

如果主题序列具有预期的形式,并且base的值为零,则根据6.4.4.1的规则,将以第一个数字开头的字符序列解释为整数常量. [...] 如果主题序列以减号开头,则转换结果取反(返回类型).

If the subject sequence has the expected form and the value of base is zero, the sequence of characters starting with the first digit is interpreted as an integer constant according to the rules of 6.4.4.1. [...] If the subject sequence begins with a minus sign, the value resulting from the conversion is negated (in the return type).

这篇关于是否应该通过std :: cin将负数读入未签名失败(gcc,clang不同意)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆