【问题标题】:How is (cin) evaluated?如何评估 (cin)?
【发布时间】:2014-03-11 22:58:25
【问题描述】:

在 Bjarne Stroustrup 的 Programming Principles and Practice Using C++(第六次印刷,2012 年 11 月) 中,if (cin)if (!cin) 在 p.148 中介绍,并在 p.178 中认真使用。 while (cin)在第183页介绍,在第201页认真使用。

但是,我觉得我并不完全了解这些构造的工作原理,所以我正在探索它们。

如果我编译并运行它:

int main()
{
        int i = 0 ;
        while (cin) {
                cout << "> ";
                cin >> i ;
                cout << i << '\n';
        }
}

我得到类似的东西:

$ ./spike_001
> 42
42
> foo
0
$
  • 为什么输入“foo”显然会导致i 被设置为0
  • 为什么输入“foo”会导致cin被设置为false

或者,如果我运行并编译它:

int main()
{
        int i = 0 ;
        while (true) {
                cout << "> ";
                cin >> i ;
                cout << i << '\n';
        }
}

我得到类似的东西:

$ ./spike_001
> 42
42
> foo
> 0
> 0
...

这里用户输入的最后一部分是foo。输入之后,&gt; 0 行会被程序反复打印到 stdout,直到被 Ctrl+C 停止。

  • 再次,为什么输入“foo”会导致i 被设置为0
  • 为什么在输入foo 后,在while 循环的下一次迭代中没有提示用户输入i 的新值?

这是使用g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

很抱歉问了这么长的问题,但我认为这一切都归结为“如何评估 cin?”

【问题讨论】:

  • 您需要检查错误标志。问题是您试图将字符串"foo" 输入整数icin 通常在使用 &gt;&gt; 运算符时执行必要的类型转换,但无法将 "foo" 转换为 int。

标签: c++


【解决方案1】:

好吧,std::cin(或更准确地说是std::basic_ios)有一个operator bool,可以在请求时将std::cin 对象隐式转换为bool(例如在您的if 评估中)。

语义如下:

检查流是否没有错误。如果流没有错误并且准备好进行 I/O 操作,则返回 true。具体来说,返回!fail()


为什么输入“foo”显然会导致 i 被设置为 0?

再次,为什么输入“foo”显然会导致 i 被设置为 0?

因为int 上的operator&gt;&gt; 需要字符串中的整数。

来自cppreference

如果提取失败(例如,如果在需要数字的地方输入了字母),则值保持不变并设置失败位。


为什么输入“foo”会导致cin被设置为false?

因为设置了失败位,所以导致fail()返回true


为什么在输入 foo 后,在 while 循环的下一次迭代中没有提示用户为 i 输入新值?

那是因为std::cin 设置了失败位,因此它无法获取输入并仅打印i 的旧值0

【讨论】:

  • 谢谢 :) 你说,“如果提取失败(例如,如果在需要数字的地方输入了一个字母),则值保持不变......”但值 不是 保持不变:而是从(例如)42 更改为 0
  • 啊,从the cppreference page you linked,我看到“自 C++11 以来”,“如果提取失败,将零写入值并设置故障位。”所以,我猜编译器默认为 C++11 :)
  • @sampablokuper,当对标准库有疑问时,只需转向cppreference。这是一个很好的来源。 :)
【解决方案2】:

当您在流上使用&gt;&gt; 运算符时,它尝试从字符串中提取该类型的值。换句话说,当您执行cin &gt;&gt; i 时,其中iint,流会尝试从流中提取int。如果成功,i 将设置为提取的值,一切正常。如果失败,则设置流的badbit。这很重要,因为将流视为布尔值等同于检查它是否设置了 badbitif (cin) 就像 if (cin.good()))。

所以无论如何......正在发生的事情是 foo 正在设置 badbit,因为提取失败。真的,您应该直接检查提取是否成功:

if (cin >> i) { /* success */ }

关于代码质量说明,我怀疑您使用的是using namespace std;。请注意这个can be harmful

【讨论】:

  • 谢谢。 if (cin &gt;&gt; i) 对我来说已经很直观了,但是尽管 Stroustrup 在某些情况下使用它,但他在我提到的页面上的示例中并没有使用它。既然我想理解所有的例子,那就意味着我还需要理解if (cin)while (cin)
  • @sampablokuper 如果有帮助的话,流上的operator&gt;&gt; 实际上会返回自己。所以cin &gt;&gt; i 的返回是cin。这就是允许隐式布尔转换的原因,也允许您执行更复杂的链接,例如 cin &gt;&gt; i &gt;&gt; s &gt;&gt; f &gt;&gt; ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
  • 1970-01-01
  • 2013-01-07
  • 2023-03-23
  • 2021-12-01
  • 2011-08-14
相关资源
最近更新 更多