【问题标题】:Clarification regarding use of flagbit to set internal error flag关于使用标志位设置内部错误标志的说明
【发布时间】:2023-03-13 02:22:01
【问题描述】:

在 C++ 入门中,我发现了这段代码:

 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 状态”,但 IMO clear(istream::failbit) 正在设置 stream 的当前状态,其值包含在失败位。那么为什么这本书将流的状态设置为 failbit 的状态,因为它将阻止 cin 运行,因为它将处于错误状态。 ++++ 根据流的状态,实际上在谈论什么位,是 eofbit、badbit、goodbit、failbit 还是它们的组合?我怎样才能知道这些个别位的价值?

【问题讨论】:

标签: c++ io


【解决方案1】:

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,因此方法good()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() 就可以了,但是我们需要创建自己的标志来让我们做出正确的反应。

流的“状态”是std::ios_base::iostate 类型的私有字段,其值等于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()。 本质上,fail()(rdstate()|std::ios_base::failbit) != 0 时返回 true,依此类推(参见 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 表示输入或输出序列的完整性丢失(例如文件中不可恢复的读取错误);
  • eofbit 表示输入操作到达了输入序列的末尾;
  • failbit 表示输入操作未能读取预期的字符,或者输出操作未能生成 所需的字符。

【讨论】:

  • 好的,现在我明白了——所以人们可以清除一些特定的位(无论是这些位中的任何一个:failbit、goodbit、eofbit、badbit)然后设置它——特别提到那个位的名称/标记为 clear() 的参数。但是如何清除标志并保持错误状态?
  • @Gaurav 添加了示例,我怀疑您正在查看的示例代码中有类似的内容
  • 还有一件事 - 当我打印 flagbit 的值时,正在打印什么值 - 对应于位值的十进制值?
  • @Gaurav 你的意思是state返回的值吗?那么是的,这是您可以使用的位常量(badbitfailbiteofbit)的按位或结果,它们的值是实现定义的,goodbit 始终定义为 0。
  • @Gauarev 这些都是常数! std::istream::failbit 是所有输入类都继承的静态成员常量。实际状态由方法rdstate() 返回,它的每一位都由这些访问器返回
猜你喜欢
  • 1970-01-01
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
  • 2016-08-03
  • 1970-01-01
  • 2020-10-04
相关资源
最近更新 更多