[英]istream eof discrepancy between libc++ and libstdc++
当与libstdc ++和libc ++链接时,以下(玩具)程序返回不同的东西。 这是libc ++中的错误还是我不明白istream eof()是如何工作的? 我尝试在linux和mac os x上使用g ++并在mac os x上运行它,使用和不使用-std = c ++ 0x。 我的印象是,在尝试读取(通过get()或其他东西)实际上失败之前,eof()不会返回true。 这就是libstdc ++的行为方式,而不是libc ++的行为方式。
#include <iostream>
#include <sstream>
int main() {
std::stringstream s;
s << "a";
std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl;
std::cout << "get: " << s.get() << std::endl;
std::cout << "EOF? " << (s.eof() ? "T" : "F") << std::endl;
return 0;
}
Thor:~$ g++ test.cpp
Thor:~$ ./a.out
EOF? F
get: 97
EOF? F
Thor:~$ clang++ -std=c++0x -stdlib=libstdc++ test.cpp
Thor:~$ ./a.out
EOF? F
get: 97
EOF? F
Thor:~$ clang++ -std=c++0x -stdlib=libc++ test.cpp
Thor:~$ ./a.out
EOF? F
get: 97
EOF? T
Thor:~$ clang++ -stdlib=libc++ test.cpp
Thor:~$ ./a.out
EOF? F
get: 97
EOF? T
编辑 :这是由于旧版本的libc ++解释C ++标准的方式。 LWG问题2036讨论了这种解释,它被认为是不正确的,并且libc ++被改变了。
当前的libc ++在测试中给出了与libstdc ++相同的结果。
老答案:
你的理解是正确的。
istream::get()
执行以下操作:
good()
,如果返回false则设置failbit
(这会将failbit添加到具有其他位设置的流中),( §27.7.2.1.2[istream::sentry]/2
) good()
为false,则返回eof并且不执行任何其他操作。 rdbuf()->sbumpc()
或rdbuf()->sgetc()
§27.7.2.1[istream]/2
) sbumpc()
或sgetc()
返回eof,则设置eofbit
。 ( §27.7.2.1[istream]/3
)和failbit
( §27.7.2.2.3[istream.unformatted]/4
) §27.7.2.2.3[istream.unformatted]/1
)并在允许的情况下重新抛出。 (引自C ++ 11的章节,但C ++ 03具有所有相同的规则,根据§27.6。*)
现在让我们来看看实现:
libc ++(当前的svn版本)定义了get()的相关部分
sentry __s(*this, true);
if (__s)
{
__r = this->rdbuf()->sbumpc();
if (traits_type::eq_int_type(__r, traits_type::eof()))
this->setstate(ios_base::failbit | ios_base::eofbit);
else
__gc_ = 1;
}
libstdc ++(与gcc 4.6.2一起提供)定义了与之相同的部分
sentry __cerb(*this, true);
if (__cerb)
{
__try
{
__c = this->rdbuf()->sbumpc();
// 27.6.1.1 paragraph 3
if (!traits_type::eq_int_type(__c, __eof))
_M_gcount = 1;
else
__err |= ios_base::eofbit;
}
[...]
if (!_M_gcount)
__err |= ios_base::failbit;
如您所见,当且仅当sbumpc()返回eof时,两个库都调用sbumpc()
并设置eofbit。
您的测试用例使用两个库的最新版本为我生成相同的输出。
这是一个libc ++错误,已被修正为Cubbi指出。 我的错。 细节在这里:
s.eof()
的值在第二次调用中未指定 - 它可能是true或false,甚至可能不一致。 你可以说的是,如果s.eof()
返回true,则所有未来的输入都将失败(但如果它返回false,则无法保证将来的输入会成功)。 失败后( s.fail()
),如果s.eof()
返回true,则可能(但不是100%确定)失败是由文件结束引起的。 但是,值得考虑以下情况:
double test;
std::istringstream s1("");
s1 >> test;
std::cout << (s1.fail() ? "T" : "F") << (s1.eof() ? "T" : "F") << endl;
std::istringstream s2("1.e-");
s2 >> test;
std::cout << (s2.fail() ? "T" : "F") << (s2.eof() ? "T" : "F") << endl;
在我的机器上,两行都是"TT"
,尽管第一次失败是因为没有数据(文件结束),第二次是因为浮点值格式不正确。
当有一个试图读取超过文件末尾的操作时,设置eofbit,操作可能不会失败(如果你正在读取整数并且整数后没有行结束,我希望eofbit被设置但是读取要成功的整数)。 IE我得到并期待FT
#include <iostream>
#include <sstream>
int main() {
std::stringstream s("12");
int i;
s >> i;
std::cout << (s.fail() ? "T" : "F") << (s.eof() ? "T" : "F") << std::endl;
return 0;
}
在这里,我不希望istream :: get尝试在返回的字符后读取(即我不希望它挂起,直到我进入下一行,如果我用它读取\\ n),所以libstd ++似乎确实是对的,至少在QOI POV中。
istream :: get的标准描述只是说“提取一个字符c,如果有一个可用”而没有描述如何以及似乎没有阻止libc ++行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.