CS253: Software Development with C++

Fall 2022

Ios State Flags

Show Lecture.IosStateFlags as a slide show.

CS253 Ios State Flags

Overview

ios State Flags

Summary of flags

ios::eofbit

ios::eofbit

ifstream in("/dev/null");
if (in.rdstate() & ios::eofbit)  cout << "Before, eofbit\n";
if (in.rdstate() & ios::failbit) cout << "Before, failbit\n";
if (in.rdstate() & ios::badbit)  cout << "Before, badbit\n";
char c;
in.get(c);
if (in.rdstate() & ios::eofbit)  cout << "After, eofbit\n";
if (in.rdstate() & ios::failbit) cout << "After, failbit\n";
if (in.rdstate() & ios::badbit)  cout << "After, badbit\n";
After, eofbit
After, failbit

eofbit ≡ hit eof trying to read; failbit ≡ tried to do something (get a char) and couldn’t.

These are bit masking operations. .rdstate() returns an integer with, perhaps, several bits set. And-ing (&) that value with one particular bit, such as ios::eofbit, will yield non-zero (true) if that bit is set, and zero (false) if if isn’t.

ios::failbit

ifstream in("/etc/hostname");
float f;
in >> f;
if (in.rdstate() & ios::eofbit)  cout << "After, eofbit\n";
if (in.rdstate() & ios::failbit) cout << "After, failbit\n";
if (in.rdstate() & ios::badbit)  cout << "After, badbit\n";
After, failbit

ios::failbit upon open failure

Also, ios::failbit is set when a file can’t be opened.

ifstream in("/this/file/doesn’t/exist");
if (in.rdstate() & ios::eofbit)  cout << "eofbit\n";
if (in.rdstate() & ios::failbit) cout << "failbit\n";
if (in.rdstate() & ios::badbit)  cout << "badbit\n";
failbit

ios::badbit

ofstream out("/dev/full");
if (out.rdstate() & ios::eofbit)  cout << "Before, eofbit\n";
if (out.rdstate() & ios::failbit) cout << "Before, failbit\n";
if (out.rdstate() & ios::badbit)  cout << "Before, badbit\n";
out << "foo" << flush;  // Force writing now, not later.
if (out.rdstate() & ios::eofbit)  cout << "After, eofbit\n";
if (out.rdstate() & ios::failbit) cout << "After, failbit\n";
if (out.rdstate() & ios::badbit)  cout << "After, badbit\n";
After, badbit

The bits are sticky

ifstream in("/etc/hostname");
double d;
in >> d;
if (in.rdstate() & ios::failbit) cout << "#1: failbit\n";
char c;
in >> c;
if (in.rdstate() & ios::failbit) cout << "#2: failbit\n";
#1: failbit
#2: failbit

Clearing bits

ifstream in("/etc/hostname");
double d;
in >> d;
if (in.rdstate() & ios::failbit) cout << "#1: failbit\n";
char c;
in >> c;
if (in.rdstate() & ios::failbit) cout << "#2: failbit\n";
in.clear();
in >> c;
if (in.rdstate() & ios::failbit) cout << "#3: failbit\n";
cout << "c=‘" << c << "’\n";
#1: failbit
#2: failbit
c=‘b’

ios::clear() clears ios::badbit, ios::eofbit, and ios::failbit.

Setting bits

Despite its name, if you give ios::clear() an argument, it sets the state of a stream to exactly those bits:

// I want to set failbit=1, eofbit=0, badbit=0:
cin.clear(ios::failbit);

Another method, ios::setstate(), sets sets only a particular bit.

// I want to set failbit=1, and leave the other bits unchanged.
cin.setstate(ios::failbit);

ios::clear() and ios::setstate() are useful when writing your own operator>> input operator for your own class. Sometimes you want to indicate a failure, or forgive a failure and try again.

Interrogating bits

The previous slides have been interrogating the bits in a straightforward, but clumsy fashion. There are several other ways:

How Results
stream.rdstate() ios::eofbit|ios::badbit|ios::failbit
stream.good() true iff no bits are set
stream.eof() true iff ios::eofbit is set
stream.bad() true iff ios::badbit is set
stream.fail() true iff ios::badbit or ios::failbit is set 😲 🤯
! stream .fail()
stream in boolean context !.fail()

Use of .fail()

$ cat /proc/uptime
6203907.30 73297872.29

The .fail() method is sometimes misused:

ifstream in("/proc/uptime");
for (float f; in >> f; )
    cout << "Read a number: " << f << '\n';

if (in.fail())  // 🦡
    cerr << "failure!\n";
Read a number: 6.20391e+06
Read a number: 7.32979e+07
failure!
Why did it fail?

Because the final read in the loop failed. If no reads in the loop failed, then we’d still be in the loop. So, this call to .fail() always succeeds—not useful.

Advice

$ cat /proc/uptime
6203907.31 73297872.48

Use boolean context instead of .is_open() or .fail(). For error checking, use the technique described at the end of the Introduction to I/O Streams lecture.

ifstream in("/proc/uptime");
if (!in) {
    cerr << "Can’t open /proc/uptime for reading\n";
    return 1;
}

int v;
while (v=1, in >> v)
    cout << "Read a number: " << v << '\n';

// All done reading.  Why did we stop?
// Bad data will set the variable to ±∞ or zero.
if (v != 1)
    cerr << "Bad data!\n";
Read a number: 6203907
Bad data!