cin.eof()和feof(stdin)是不一致的

时间:2018-04-17 14:26:34

标签: c++ input eof

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

1 个答案:

答案 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询问}将报告文件结束条件,cinstdin都将设置文件内部结束标志。然后调用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标志和将文件结束条件返回cincin设置自己的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()是错误的。