gpt4 book ai didi

c++ - C++ 的 istream::eof() 的不一致是规范中的错误还是实现中的错误?

转载 作者:可可西里 更新时间:2023-11-01 17:22:56 29 4
gpt4 key购买 nike

以下程序演示了 std::istream(特别是在我的测试代码中,std::istringstream)设置 eof() 的方式不一致。

#include <sstream>
#include <cassert>

int main(int argc, const char * argv[])
{
// EXHIBIT A:
{
// An empty stream doesn't recognize that it's empty...
std::istringstream stream( "" );
assert( !stream.eof() ); // (Not yet EOF. Maybe should be.)
// ...until I read from it:
const int c = stream.get();
assert( c < 0 ); // (We received garbage.)
assert( stream.eof() ); // (Now we're EOF.)
}
// THE MORAL: EOF only happens when actually attempting to read PAST the end of the stream.

// EXHIBIT B:
{
// A stream that still has data beyond the current read position...
std::istringstream stream( "c" );
assert( !stream.eof() ); // (Clearly not yet EOF.)
// ... clearly isn't eof(). But when I read the last character...
const int c = stream.get();
assert( c == 'c' ); // (We received something legit.)
assert( !stream.eof() ); // (But we're already EOF?! THIS ASSERT FAILS.)
}
// THE MORAL: EOF happens when reading the character BEFORE the end of the stream.

// Conclusion: MADNESS.
return 0;
}

因此,当您读取实际文件结尾之前的字符时,eof()“触发”。但是如果流是空的,它只会在您实际尝试读取字符时触发。 eof() 的意思是“你只是想读完结尾吗?”或“如果您再次尝试阅读,您会读完吗?”答案不一致。

此外,断言是否触发取决于编译器。例如,Apple Clang 4.1 触发断言(在读取前面的字符时引发 eof())。例如,GCC 4.7.2 就没有。

这种不一致使得编写读取流但同时处理空流和非空流的合理循环变得困难。

选项 1:

while( stream && !stream.eof() )
{
const int c = stream.get(); // BUG: Wrong if stream was empty before the loop.
// ...
}

选项 2:

while( stream )
{
const int c = stream.get();
if( stream.eof() )
{
// BUG: Wrong when c in fact got the last character of the stream.
break;
}
// ...
}

那么, friend 们,我该如何编写一个循环来解析一个流,依次处理每个字符,处理每个字符,但是当我们到达 EOF 或流为空时毫不费力地停止开始,永远不会开始?

好吧,更深层次的问题:我的直觉是使用 peek() 可能会以某种方式解决这个 eo​​f() 不一致问题,但是......天哪!为什么不一致?

最佳答案

eof() 标志仅用于确定您是否在 某些操作后到达文件末尾。主要用途是在读取合理失败时避免出现错误消息,因为没有更多内容可读取。尝试使用 eof() 控制循环或其他东西注定会失败。在所有情况下,您都需要在尝试读取后检查读取是否成功。在尝试之前,流无法知道您将要阅读什么。

eof() 的语义被彻底定义为“当读取流导致流缓冲区返回失败时设置此标志”。如果我没记错的话,要找到这个陈述并不那么容易,但这就是结果。在某些时候,该标准还表示,在某些情况下,允许流读取的内容多于它必须读取的内容,这可能会导致 eof() 在您不一定期望的情况下被设置。一个这样的例子是读取一个字符:流可能最终检测到该字符后面没有任何内容并设置 eof()

如果你想处理一个空流,这很简单:从流中查看一些东西,只有当你知道它不为空时才继续:

if (stream.peek() != std::char_traits<char>::eof()) {
do_what_needs_to_be_done_for_a_non_empty_stream();
}
else {
do_something_else();
}

关于c++ - C++ 的 istream::eof() 的不一致是规范中的错误还是实现中的错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13204364/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com