C++ C++;eof上的istream tellg()/fail():行为更改;工作?
我将编译器从gcc-4.4升级到gcc-4.8,一个项目由于以下(错误)假设而惨遭失败:C++ C++;eof上的istream tellg()/fail():行为更改;工作?,c++,qt,gcc,istream,C++,Qt,Gcc,Istream,我将编译器从gcc-4.4升级到gcc-4.8,一个项目由于以下(错误)假设而惨遭失败: #include <sstream> #include <assert.h> int main() { using namespace std; istringstream iScan; int num; //iScan.unsetf(std::ios::skipws); iScan.str("5678"); iScan >&
#include <sstream>
#include <assert.h>
int main()
{
using namespace std;
istringstream iScan;
int num;
//iScan.unsetf(std::ios::skipws);
iScan.str("5678");
iScan >> num;
assert(iScan.tellg() == istringstream::pos_type(4));
assert(!iScan.fail());
assert(!iScan.good());
assert(iScan.eof());
assert(num == 5678);
assert(false && "We passed the above assertions.");
return 0;
}
#包括
#包括还是其他?(还有哪个?)
是否有一个全球性的、可靠的、独立于语言的工作环境?(我猜不是。)
是否有一个全球性的、可靠的、跨版本的gcc工作环境
即使我完成了上面的unset(skipws),它仍然不能在gcc-4.8上工作。那不是不正确的行为吗
此外,各种在线编译器提供不同的行为。这是他们库的功能吗
- ,它声称是gcc-4.7.2,允许它,即使其他消息来源说行为在4.6中发生了变化
- ,gcc-4.8,显示了新的行为,而unset(skipws)似乎没有效果
- 允许。不知道版本
其他类似但不重复的问题:
代码的主体非常庞大,所有这些假设都贯穿其中
更新:以下是答案的关键部分,它应该适用于所有版本、所有编译器:
// istream::tellg() is unreliable at eof(): works w/gcc-4.4, doesn't w/gcc-4.8.
#include <sstream>
#include <assert.h>
using namespace std;
typedef istream::pos_type pos_type;
pos_type reliable_tellg(istream &iScan)
{
bool wasEOF = iScan.eof();
if (wasEOF)
iScan.clear(iScan.rdstate() & ~ios::eofbit); // so tellg() works.
pos_type r = iScan.tellg();
if (wasEOF)
iScan.clear(iScan.rdstate() | ios::eofbit); // restore it.
return r;
}
int main()
{
istringstream iScan;
int num, n2;
//iScan.unsetf(std::ios::skipws);
iScan.str("5678");
assert(!iScan.eof() && !iScan.fail()); // pre-conditions.
assert(reliable_tellg(iScan) == pos_type(0));
iScan >> num;
assert(!iScan.fail());
assert(reliable_tellg(iScan) == pos_type(4));
assert(iScan.eof());
assert(reliable_tellg(iScan) == pos_type(4)); // previous calls don't bungle it.
assert(num == 5678);
iScan >> n2; // at eof(), so this should fail.
assert(iScan.fail());
assert(reliable_tellg(iScan) == pos_type(-1)); // as expected on fail()
assert(iScan.eof());
assert(false && "We passed the above assertions.");
return 0;
}
//istream::tellg()在eof()上不可靠:工作时使用的是/gcc-4.4,而不是w/gcc-4.8。
#包括
#包括
使用名称空间std;
typedef istream::pos_type pos_type;
pos型可靠信号(istream和iScan)
{
bool wasEOF=iScan.eof();
如果(wasEOF)
iScan.clear(iScan.rdstate()&~ios::eofbit);//因此tellg()可以工作。
pos_type r=iScan.tellg();
如果(wasEOF)
iScan.clear(iScan.rdstate()| ios::eofbit);//还原它。
返回r;
}
int main()
{
istringstream iScan;
int num,n2;
//iScan.unset(std::ios::skipws);
iScan.str(“5678”);
断言(!iScan.eof()&&!iScan.fail());//前置条件。
断言(可靠测试(iScan)=位置类型(0));
iScan>>num;
断言(!iScan.fail());
断言(可靠测试(iScan)=位置类型(4));
断言(iScan.eof());
assert(reliable_tellg(iScan)=pos_type(4));//以前的调用不会把它搞砸。
断言(num==5678);
iScan>>n2;//在eof()处,因此此操作应该失败。
断言(iScan.fail());
assert(reliable_tellg(iScan)==pos_type(-1));//如失败时所预期的()
断言(iScan.eof());
断言(false&“我们通过了上述断言”);
返回0;
}
您似乎期望的行为可能是错误的。都是C++11
而C++03则以“行为类似于
未格式化输入函数[…]”。“无格式输入”
函数“首先构造一个sentry
对象,然后
失败,不执行任何操作并返回失败状态,如果
sentry
对象转换为false
。以及哨兵
对象
如果设置了eofbit
,则将转换为false
标准对是否阅读
数字设置了eofbit
,但仅稍微设置了一点(使用
信息分布在几个不同的部分)。
基本上,当输入数值时,流(实际上,
num_get
facet)必须在前面读取一个字符,以便
知道数字的终点。在你的情况下,它将看到结局
发生这种情况时,将设置为eofbit
。那么你的
第一个assert
将以一致性实现失败
可以很容易地认为这是标准中的缺陷,或者
无意的。很容易想象一些实现
做明智的事情(这似乎是你所期望的),
也许是因为最初的实现者没有意识到
标准中的全部含义(或无意识地将其理解为
他们认为应该把它读出来)。我猜这就是
当他们意识到自己的行为是
不一致,他们修正了它
至于工作环境。。。我不确定真正的问题是什么,
你正在努力解决这个问题。但我认为如果你
清除tellg
之前的错误位,它应该可以工作。(关于
当然,那么iScan.good()
将是true
,而iScan.eof()
false
。但这真的有关系吗?)一定要检查一下
在你清除数据之前,提取确实成功了
状态。那么,正如您所说,在前面读取一个字符时,规范是否明确规定数字在eof结束时不会失败?在eof,即使您清除eofbit,调用tellg()也只会再次设置它,不是吗?@JimB标准是明确的。转换数值时,将提取字符,直到遇到文件的任意一端,或看到不能作为数字(任何类型或基数)一部分的字符。如果此提取过程因文件结束而终止,则设置eofbit
。(这在第22.4.2.1.2节第3段第2阶段中进行了描述。)@JimB No.eofbit
的设置是因为试图读取字符(提取或不提取字符)导致文件结束tellg
不尝试读取字符。eofbit
不是预测性的。它不会被设置,因为下一次读取将看到文件的结尾,它被设置是因为尝试(内部)读取字符失败;调用streambuf::sgets
,streambuf::sbumps
或streambuf::snexts
已返回EOF
。