55

来自 Stroustrup 的 TC++PL,第 3 版,第 21.3.3 节:

如果我们尝试读入变量 v 并且操作失败,则 v 的值应该保持不变(如果 v 是 istream 或 ostream 成员函数处理的类型之一,则它不变)。

下面的例子似乎与上面的引用相矛盾。根据上面的引用,我期望 v 的值保持不变——但它会归零。这种明显矛盾的行为的解释是什么?

#include <iostream>
#include <sstream>

int main( )
{
    std::stringstream  ss;

    ss  << "The quick brown fox.";

    int  v = 123;

    std::cout << "Before: " << v << "\n";

    if( ss >> v )
    {
        std::cout << "Strange -- was successful at reading a word into an int!\n";
    }

    std::cout << "After: " << v << "\n";

    if( ss.rdstate() & std::stringstream::eofbit  ) std::cout << "state: eofbit\n";
    if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbit\n";
    if( ss.rdstate() & std::stringstream::badbit  ) std::cout << "state: badbit\n";

    return 1;
}

我使用 x86_64-w64-mingw32-g++.exe (rubenvb-4.7.2-release) 4.7.2 得到的输出是:

Before: 123
After: 0
state: failbit

谢谢。

4

2 回答 2

62

这个参考

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

如果提取失败,则将零写入 value 并设置 failbit。如果提取导致值太大或太小而无法放入值,则写入 std::numeric_limits::max() 或 std::numeric_limits::min() 并设置故障位标志。(自 C++11 起

您的编译器似乎在 C++11 模式下编译,这会改变行为。


输入运算符使用std::num_getget函数调用的语言环境方面do_get。对于 C++11,它指定使用std::strtollet。人。函数类型。在 C++11 之前,它显然使用std::scanf样式解析(通过参考,我无权访问 C++03 规范)来提取数字。行为的变化是由于解析输入的变化。

于 2012-11-14T12:45:20.813 回答
4

运算符 >> 是格式化的输入运算符。
因此,取决于如何从流中读取输入的语言环境:

[istream.formatted.arithmetic]

与插入器的情况一样,这些提取器依赖于语言环境的 num_get<> (22.4.2.1) 对象来执行输入流数据的解析。这些提取器表现为格式化的输入函数(如 27.7.2.2.1 中所述)。构建哨兵对象后,转换就像由以下代码片段执行一样:

   typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
   iostate err = iostate::goodbit;
   use_facet< numget >(loc).get(*this, 0, *this, err, val);
   setstate(err);

正如我们在上面看到的,该值实际上是由numget嵌入到流中的语言环境的方面设置的。

num_get 虚函数 [facet.num.get.virtuals]

第三阶段:

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

  • 零,如果转换函数无法转换整个字段。ios_base::failbit 分配给 err。
  • 最正的可表示值,如果该字段表示的值太大而无法用 val 表示。ios_base::failbit 分配给 err。
  • 如果字段表示的值太大而无法在 val 中表示,则为无符号整数类型的最大负可表示值或零。ios_base::failbit 分配给 err。

第 3 阶段的定义在 n2723 -> n2798 之间发生了巨大变化

在哪里可以找到当前的 C 或 C++ 标准文档?

num_get 虚函数 [facet.num.get.virtuals]

第 3 阶段:第 2 阶段处理的结果可以是以下之一:

  • 在阶段 2 中累积了一系列字符,这些字符被转换(根据 scanf 的规则)为 val 类型的值。该值存储在 val 中,而 ios_base::goodbit 存储在 err 中。
  • 在阶段 2 中累积的字符序列会导致 scanf 报告输入失败。ios_base::failbit 分配给 err。
于 2012-11-14T13:42:10.530 回答