来自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
感谢。
答案 0 :(得分:55)
如果提取失败(例如,如果输入了预期数字的字母),则值保持不变并设置failbit(直到C ++ 11 )
如果提取失败,则将零写入值并设置failbit。如果提取导致值太大或太小而不适合值,则写入std :: numeric_limits :: max()或std :: numeric_limits :: min()并设置failbit标志。 (,因为C ++ 11 )
您的编译器似乎正在以C ++ 11模式进行编译,这会改变行为。
输入运算符使用get
函数调用std::num_get
的区域设置构面do_get
。对于C ++ 11,它指定使用std::strtoll
et。人。功能类型。在C ++ 11之前,它显然使用std::scanf
样式解析(通过引用,我不能访问C ++ 03规范)来提取数字。行为的改变是由于解析输入时的这种变化。
答案 1 :(得分:4)
运营商&gt;&gt;是格式化的输入操作符 因此,这取决于如何从流中读取输入的区域设置:
与插入器的情况一样,这些提取器依赖于语言环境的num_get&lt;&gt; (22.4.2.1)对象执行解析输入流数据。这些提取器表现为格式化的输入函数(如27.7.2.2.1中所述)。构造sentry对象后,转换就像执行以下代码片段一样:
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
方面设置的。
第3阶段:
要存储的数值可以是以下之一:
- 零,如果转换函数无法转换整个字段。 ios_base :: failbit分配给err。
- 最正可表示的值,如果该字段表示太大而无法在val中表示的值。 ios_base :: failbit分配给err。
- 无符号整数类型的最负值可表示值或零,如果该字段表示的值太大而无法在val中表示。 ios_base :: failbit分配给err。
阶段3的定义在n2723 - &gt;之间急剧变化。 n2798
Where do I find the current C or C++ standard documents?
阶段3:阶段2处理的结果可以是以下之一:
- 在阶段2中累积了一系列字符,这些字符被转换(根据scanf的规则)为val类型的值。该值存储在val中,ios_base :: goodbit存储在err。
中- 第2阶段累积的字符序列会导致scanf报告输入失败。 ios_base :: failbit分配给err。