Show Lecture.IosStateFlags as a slide show.
CS253 Ios State Flags
Overview
- By default, streams do not throw errors when things go bad.
- Instead, they maintain several bits (flags)
that indicate the state of the stream.
- Several methods exist which interrogate the stream’s state.
ios State Flags
Summary of flags
ios::eofbit
- ios::eofbit is set when end-of-file
is encountered.
- That’s when you try to read, but can’t, because there’s no more data.
It doesn’t predict.
- Let’s try reading from the special file
/dev/null
,
which is always empty.
ifstream in("/dev/null");
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 get a char and couldn’t.
ios::failbit
- ios::failbit is set when an I/O operation fails—you didn’t get what
you wanted. Couldn’t open a file, read a number/char/string, etc.
- ios::failbit was set in the previous example, because we
tried to read a character, and couldn’t.
- Let’s try to read a float from
/etc/hostname
,
which has contains the name of this computer,
“beethoven”
(not a number).
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
- ios::badbit is not set upon a mere conversion error,
but, rather, when a low-level I/O error occurs:
the system runs out of memory, the disk becomes full, etc.
- Let’s try writing to the special file
/dev/full
,
which simulates a disk that is always full.
ofstream out("/dev/full");
out << "foo" << endl;
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
- Why doesn’t the second read succeed? Because the bits are sticky.
- Once ios::failbit is set, it stays set. It’s pouty.
- The second extraction gives up without trying,
because ios::failbit is set.
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:
in.clear(ios::failbit);
// I want to set failbit=1, and leave the other bits unchanged.
in.setstate(ios::failbit);
Interrogating bits
The previous slides have been interrogating the bits in a
straightforward, but clumsy fashion. There are several other ways:
$ cat /proc/uptime
1761245.62 20834190.52
The fail() method is sometimes misused:
ifstream in("/proc/uptime");
for (float f; in >> f; )
cout << f << '\n';
if (in.fail())
cerr << "failure!\n";
1.76125e+06
2.08342e+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
Use boolean context instead of is_open() or fail().
Only use eof() for error-checking after the loop.
ifstream in("/etc/hostname");
if (!in) {
cerr << "Can’t open /etc/hostname for reading\n";
return 1;
}
for (float f; in >> f; )
cout << "Hooray, got a number: " << f << '\n';
// All done reading. Why did we stop?
// Was it end-of-file, or did something go wrong?
// Don’t check .fail(); that’ll always be true.
if (!in.eof())
cerr << "Bad numbers!\n";
Bad numbers!