【发布时间】:2012-10-23 15:37:44
【问题描述】:
以下程序演示了 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;
}
// ...
}
那么,朋友们,我该如何编写一个循环来解析流,依次处理每个字符,处理每个字符,但在遇到 EOF 或流为空的情况下会毫不费力地停止开始,从未开始?
好吧,更深层次的问题:我有直觉认为使用 peek() 可能会以某种方式解决这个 eof() 不一致问题,但是......该死的废话!为什么不一致?
【问题讨论】:
-
你能指定什么编译器吗?您的
EXHIBIT B:行为对我来说似乎是一个错误。 -
@JesseGood:对于大多数实现来说,这似乎是正确的行为:流还没有尝试读取过去的 EOF。只有当它试图读取最后一个字符时,才需要设置
eof()。不过可以提前设置eof()。 -
@DietmarKühl:
It is allowed to set eof() earlier, though.嗯,你确定吗? -
使用多个编译器为我工作(运行完成)。
-
@DietmarKühl:你在哪里看到它可以更早地设置 eof() ?请记住,OP 使用 get(),它只读取一个字符,因此没有歧义。