读和忽略的不同EOF行为

Different EOF behavior with read versus ignore

本文关键字:EOF 行为      更新时间:2023-10-16

我最近被std::istream::readstd::istream::ignore行为之间的微妙区别绊倒了。基本上,read从输入流中提取N个字节,并将它们存储在缓冲区中。ignore函数从输入流中提取N个字节,但简单地丢弃它们,而不是将它们存储在缓冲区中。所以,我的理解是,readignore在各方面基本上是相同的,除了read保存提取的字节,而ignore只是丢弃它们。

但是readignore之间还有一个微妙的区别,这让我很困惑。如果读取到流的末尾,则不会触发EOF条件。为了触发EOF条件,必须读取流的之后的。但是使用ignore就不同了:你只需要读到流的结尾

考虑:

#include <sstream>
#include <iostream>
using namespace std;
int main()
{
    {
        std::stringstream ss;
        ss << "abcd";
        char buf[1024];
        ss.read(buf, 4);
        std::cout << "EOF: " << std::boolalpha << ss.eof() << std::endl;
    }
    {
        std::stringstream ss;
        ss << "abcd";
        ss.ignore(4);
        std::cout << "EOF: " << std::boolalpha << ss.eof() << std::endl;
    }
}

在GCC 4.4.5中,输出如下:

EOF: false
EOF: true

那么,为什么这里的行为不同?这种细微的差别让我很困惑,我想知道为什么会有这种差别。是否有一些令人信服的理由,EOF被"提前"触发,并被要求忽略?

eof()应该只在您已经尝试阅读过了结尾时返回true。这两种情况都不应该是真的。

我将在这里冒险并回答我自己的问题:这看起来真的像是GCC中的一个错误。

标准读27.6.1.3第23段:

[istream::ignore]表现为一个未格式化的输入函数(如如27.6.1.3第1段所述。在建造了一个哨兵物体之后,提取字符并丢弃它们。字符被提取,直到任意一个出现以下情况:

    如果n != numeric_limits::max()(18.2.1),提取n个字符
  • 文件结束符出现在输入序列上(在这种情况下,函数调用setstate(eofbit),它可以扔ios_base:失败(27.4.4.3)),
  • c == delim表示下一个可用的输入字符c(在这种情况下,c为提取)。注:最后一个条件将永远不会发生如果delim ==特征::eof ()

我的(有些试探性的)解释是GCC在这里是错误的,因为上面的粗体部分。Ignore应该表现为未格式化的输入函数(如read()),这意味着只有在(流中最后一个字节已被提取)之后试图提取额外的字节时,文件结束才应该出现在输入序列上。

如果我发现有足够多的人同意这个答案,我将提交一个错误报告。

大家一致认为这是gcc中一个合理的错误。由于我没有看到任何提交bug报告的迹象,所以我现在正在这样做。该报告可在以下网址查看:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51651