Can feof(stdin)
and cin.eof()
produce discordant results? I would expect them not to do so, but I guess I am missing something. Does the standard say anything about this?
Consider the following example, when no input is given. This can either be done by typing the shortcut for EOF in the terminal, or by redirecting the input on /dev/null
(Unix), or with empty stdin sequence on ideone.com...
#include <cstdio>
#include <iostream>
int main() {
using namespace std;
char ch;
cin >> ch;
cin.clear();
cout << boolalpha
<< "feof(stdin): " << bool(feof(stdin)) << endl
<< "cin.eof(): " << cin.eof() << endl;
}
Output:
feof(stdin): true
cin.eof(): false
Well, there is no surprise here.
std::cin
is truely defined in the C++ library, but stdin
is defined in the C standard library that is member of the C++ one mainly for compatibility reasons.
Draft n4659 for C++17 says:
30.4.3 Narrow stream objects [narrow.stream.objects]
istream cin;
1 The object cin controls input from a stream buffer associated with the object stdin
, declared in
(30.11.1).
and later:
30.11 C library files [c.files]
30.11.1 Header <cstdio>
synopsis [cstdio.syn]
...
1 The contents and meaning of the header <cstdio>
are the same as the C standard library header <stdio.h>
.
That means that cin
is a C++ stream wrapping the underlying stdin
C FILE object. As a result, when you try to read a character from cin
after reaching the end of file, cin
will ask it from stdin
, stdin
will report an end of file condition and both cin
and stdin
will set their internal end of file flag. Then the call to cin.clear()
clears the C++ stream flag but it is unspecified whether it has an action on the stdin
object internal flag.
So you are responsable for the lack of synchronization between the C++ cin
object and the C stdin
one.
Now for the details on what happens in this code copied from your ideone:
#include <cstdio>
#include <iostream>
// first type the shortcut for EOF, then a single character
int main() {
using namespace std;
char ch;
cin >> ch; // 1
cin.clear(); // 2
cout << boolalpha // 3
<< "feof(stdin): " << bool(feof(stdin)) << endl
<< "cin.eof(): " << cin.eof() << endl;
ch = char(getchar()); // 4
cout << ch << endl; // 5
cout << boolalpha // 6
<< "feof(stdin): " << bool(feof(stdin)) << endl
<< "cin.eof(): " << cin.eof() << endl;
}
//1 : you read a char from cin
(ignoring the char): cin internally read from stdin
, stdin
finds an end of file, sets its internal EOF flag and return an end of file condition to cin
. cin
sets its own EOF flag
//2 : you clear the EOF flag on cin
, stdin
is unchanged (in this implementation since behaviour is unspecified by standard AFAIK)
//3 : as expected feof(stdin)
is true and cin.eof()
is false
//4 : you read a char from stdin
(cin
is untouched here). As you are already at end of file, getchar returns the integer constant EOF = -1. But as you force a conversion to char -1 is converted to '\xff'
, ASCII char DEL
//5 : '\xff'
is not a valid UTF8 sequence and ideone displays it as the unicode REPLACEMENT CHARACTER �
//6 : feof(stdin)
is still true: the C FILE has reached end of file, and cin.eof()
is still false because nothing changed it since //3
TL/DR: everything is as expected: the underlying file as reached end of file and getchar()
does return EOF, and the eof flags are set. Simply as you explicitely clear cin
flags and never use it later cin.eof()
is false.