c++ - 关于使用标志位设置内部错误标志的说明

标签 c++ io

在 C++ primer 中我找到了这段代码:

 if (cin.fail())
 { // bad input
      cerr<< "bad data, try again"; // warn the user
      cin.clear(istream::failbit); // reset the stream
      continue; // get next input
 }

我很困惑为什么 istream::failbit 用于设置错误状态标志,我的意思是因为错误已经发生(因此流程现在在 if 阻止然后必须设置 failbit,他们为什么要用它来再次设置错误标志。我理解这个错误在哪里?

编辑: 这本书说“我们打印警告并清除 failbit 状态”,但 IMO clear(istream::failbit) 正在使用包含的值设置 stream 的当前状态故障位。那么为什么这本书将流的状态设置为 failbit 的状态,因为它将阻止 cin 运行,因为它将处于错误状态。 ++++ 根据流的状态,实际讨论的是什么位,是eofbit、badbit、goodbit、failbit 还是它们的组合?我如何才能知道这些单个位的值(value)?

最佳答案

std::basic_ios::clear

void clear( std::ios_base::iostate state = std::ios_base::goodbit ); 

通过为它们分配state 的值来设置流错误状态标志。默认情况下,分配具有清除所有错误状态标志的效果的 std::ios_base::goodbit

如果 rdbuf() 是空指针(即没有关联的流缓冲区),则 state | badbit 已分配。可能会抛出异常。

本质上,在这种情况下,设置位意味着它将位设置为清除状态。

如果您不带参数调用 clear,它会通过设置“goodbit”将所有位设置为清除状态,这与其他状态是互斥的。如果您只标记某个位,则只会设置该位,清除其他位(​​以及好的位)。无论如何,如上所述,如果在调用此方法期间流的输入缓冲区无效,则 clear() 还将 badbit 设置为 true,因此方法 很好()operator bool 将返回 falsefail() 仍将返回 true

也就是说,为什么需要清除这些位但保持错误状态取决于进一步的代码,通常是为了能够检测到发生的错误,但能够从流中请求更多数据(要求正确输入?)

#include <iostream>
#include <limits> 
#include <string> 
int main() {
    using std::cout;
    using std::cin;

    int a;
    do
    {
        cout << " Please enter an integer number:";
        cin.clear();
        cin >> a;
        if(cin.fail())
        {
            cout << "Error occured while parsing input.\n";
            cin.clear(std::istream::failbit);
        }


        // do something

        if(cin.fail())
        {
            std::string str;
                    //now clear everything,  to unlock the input.
            cin.clear(); 
            cin >> str;
            cout << "Wrong input was: " << str << "\n";
            cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
                    // setting fail bit again, so   loop will go on
            cin.clear(std::istream::failbit);
        }

    } while(cin.fail());
    cout << "Thank you!";
}

如果不调用 ::clear(std::istream::failbit)::ignore 循环将永远有效,因为标志和缓冲区的状态将强制尝试一遍又一遍地解析相同的缓冲区内容。实际上,那一点你可以尝试重新解析它,例如读取字符串并打印出来。只调用 clear() 是可以的,但是我们需要创建自己的标志,让我们能够做出正确的 react 。

流的“状态”是一个类型为std::ios_base::iostate的私有(private)字段,其值等于它的二进制组合eofbitbadbitfailbit 常量。 goodbit 常量等于零,表示无错误状态。为该字段提供读写操作的两个访问器:

void setstate( iostate state );
iostate rdstate() const;

注意,setstate(state)得到了clear(rdstate() | state)的效果,这意味着如果clear可以精确设置iostate的值,setstate只能设置新的位为真,不能清除已经设置的位。

int main()
{
  std::ostringstream stream;

  if (stream.rdstate() == std::ios_base::goodbit) {
    std::cout << "stream state is goodbit\n";
  }

  stream.setstate(std::ios_base::eofbit);

  // check state is exactly eofbit (no failbit and no badbit)
  if (stream.rdstate() == std::ios_base::eofbit) {
    std::cout << "stream state is eofbit\n";
  }
}

对于每一位都有访问器:fail()bad()eof()good()。 本质上,如果 (rdstate()|std::ios_base::failbit) != 0 等,则 fail() 返回真(参见 30.5.5.4 basic_ios 标志函数, ISO/IEC 14882:2017, 编程 语言——C++)

  • operator bool 被定义并返回 good()
  • operator! 被定义并返回 !good()

线

if (stream.rdstate() == std::ios_base::goodbit)

可以替换为

if (stream)

因为后者会导致上下文转换为 bool

效果,与 iostate 的位相关(根据 ISO C++):

  • badbit indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error from a file);
  • eofbit indicates that an input operation reached the end of an input sequence;
  • failbit indicates that an input operation failed to read the expected characters, or that an output operation failed to generate the desired characters.

关于c++ - 关于使用标志位设置内部错误标志的说明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45647977/

相关文章:

c++ - 对二维字符数组进行排序 C++

c++ - while 条件下的预处理器指令不起作用

c++ - 一个c++语法问题(一种结构方法)

c - c 中的异步 io 使用 windows API : which method to use and why does my code execute synchronous?

java - 扫描仪在使用 next() 或 nextFoo() 后跳过 nextLine()?

c++ - 将字符串转换为 unsigned char []

c++ - 由另一个 CRTP 子类访问数据/方法

types - 为什么Go的io包中没有RuneWriter接口(interface)?

java读取并写入\u05DC为 '?'

haskell - 无法让 (->) r monad 与 SDL2 渲染一起工作