feof(stdin)
和cin.eof()
会产生不一致的结果吗?我希望他们不要这样做,但我想我错过了一些东西。标准是否对此有所说明?
在没有给出输入的情况下,请考虑以下示例。这可以通过在终端中键入EOF的快捷方式,或通过在/dev/null
(Unix)上重定向输入,或在ideone.com上使用空的stdin序列来完成...
#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;
}
输出:
feof(stdin): true
cin.eof(): false
答案 0 :(得分:2)
嗯,这里并不奇怪。
std::cin
在C ++库中是真正定义的,但{C}标准库中定义了stdin
,主要是出于兼容性原因而在C ++标准库中定义。
草案n4659 for C ++ 17说:
30.4.3窄流对象[narrow.stream.objects]
istream cin;
1对象cin控制与声明的对象
stdin
关联的流缓冲区的输入 (30.11.1)。
以后:
30.11 C库文件[c.files]
30.11.1标题<cstdio>
概要[cstdio.syn]
...
1标题<cstdio>
的内容和含义与C标准库标题<stdio.h>
相同。
这意味着cin
是C ++流包装基础stdin
C FILE对象。因此,当您在到达文件末尾后尝试从cin
读取时,cin
会从stdin
stdin
询问}将报告文件结束条件,cin
和stdin
都将设置文件内部结束标志。然后调用cin.clear()
清除C ++流标志,但未指定是否对stdin
对象内部标志执行了操作。
所以你对C ++ cin
对象和C stdin
对象之间缺乏同步负责。
现在了解从您的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:你从cin
读取了一个字符(忽略了字符):cin从stdin
内部读取,stdin
找到文件的结尾,设置其内部EOF标志和将文件结束条件返回cin
。 cin
设置自己的EOF标志
// 2:您清除了cin
上的EOF标记,stdin
未更改(在此实现中,因为行为未通过标准AFAIK指定)
// 3:按预期feof(stdin)
为真且cin.eof()
为假
// 4:您从stdin
读取了一个字符(cin
未触及此处)。由于您已经在文件末尾,getchar返回整数常量EOF = -1。但当您强制转换为char -1时会转换为'\xff'
,ASCII char DEL
// 5:'\xff'
不是有效的UTF8序列,ideone将其显示为unicode REPLACEMENTCHARACTER
// 6:feof(stdin)
仍然是正确的:C FILE已经到达文件末尾,cin.eof()
仍然是假的,因为自// 3以来没有任何改变
TL / DR:一切都如预期的那样:到达文件末尾的基础文件和getchar()
确实返回EOF,并设置了eof标志。只需明确清除cin
标记并且以后再也不使用它cin.eof()
是错误的。