gpt4 book ai didi

EOF : behavior change; work-around? 上的 C++ istream tellg()/fail()

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:26:35 25 4
gpt4 key购买 nike

我将我的编译器从 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-4.4 上,相关断言通过。在 gcc-4.8 上,tellg() 返回 -1,而 fail() 返回 !false,显然是因为它命中了 eof。

我的目标是 Qt 5.1 (gcc-4.8) 附带的 MinGW 32 位。

问题:

  • 按照 N3168 的说法,旧的行为真的是错误的吗?或其他? (还有哪个?)
  • 是否有全局、可靠、独立于语言的解决方法? (我猜不是。)
  • 是否有跨版本的全局性、可靠的 gcc 解决方法?
  • 即使我执行了上面的 unsetf(skipws),它仍然不能在 gcc-4.8 上运行。这不是不正确的行为吗?

此外,各种在线编译器给出不同的行为。这是他们的库的功能吗?

  • compileonline ,声称是 gcc-4.7.2,允许它,即使其他消息来源说行为在 4.6 中发生了变化。
  • stack-crooked , gcc-4.8, 显示了新的行为,而 unsetf(skipws) 似乎没有效果。
  • codepad允许它。无法分辨版本。

其他类似但不重复的问题:

这些假设贯穿其中的代码主体非常庞大。

更新:这是答案的关键部分,应该适用于所有版本、所有编译器:

// 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;
}

最佳答案

您似乎期望的行为可能是错误的。两者都是 C++11和 C++03 以“Behaves as an未格式化的输入函数[...]”。一个“未格式化的输入function” 从构建一个 sentry 对象开始,并将失败,什么都不做并返回失败状态,如果sentry 对象转换为 false。和 sentry 对象如果设置了 eofbit,将转换为 false

标准对于是否阅读number 设置 eofbit,但只是轻微的(与信息分布在几个不同的部分)。基本上,当输入一个数值时,流(实际上,num_get 方面)必须先读取一个字符,以便知道数字在哪里结束。在你的情况下,它将看到结束发生这种情况时的文件,因此将设置 eofbit。所以你的第一个 assert 将因符合规范的实现而失败。

人们很容易认为这是标准中的缺陷,或者无意的。很容易想象一些实现做明智的事情(这似乎是你所期望的),也许是因为最初的实现者没有意识到标准中的全部含义(或不自觉地将其读作他们认为应该阅读)。我猜这是g++ 的情况,当他们意识到他们的行为是不合规,他们修复了它。

至于解决方法...我不确定真正的问题是什么,您正在尝试解决。但我认为如果你清除tellg 之前的错误位,它应该可以工作。 (的当然,那么 iScan.good() 将是 true,而 iScan.eof()错误。但这真的很重要吗?)一定要检查一下在清除之前提取实际上成功了状态。

关于EOF : behavior change; work-around? 上的 C++ istream tellg()/fail(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18490576/

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