C++ C++;eof上的istream tellg()/fail():行为更改;工作?

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 >&

我将编译器从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 >> 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