我将编译器从 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) 似乎没有效果。
- 键盘允许它。分不清版本。
其他类似但不重复的问题:
这些假设贯穿其中的代码体很大。
更新: 这是答案的关键部分,它应该适用于所有版本,所有编译器:
// 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;
}