【问题标题】:file stream tellg/tellp and gcc-4.6 is this a bug?文件流 tellg/tellp 和 gcc-4.6 这是一个错误吗?
【发布时间】:2011-07-01 20:23:56
【问题描述】:

这段代码:

#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>

int main()
{   
    std::remove("test.txt");
    std::fstream f("test.txt",std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc);
    std::cout << f.good() << std::endl;
    f<<"test"<< std::flush;
    std::cout << f.tellg() << " " << f.tellp() << std::endl;
    f.seekg(0);
    std::string s;
    f>>s;
    std::cout << f.tellg() << " " << f.tellp() << std::endl;
}   

在 gcc-4.4.5 中给出以下输出

1
4 4
4 4

即tellg 和 tellp 都返回了预期的流位置 4。

虽然 gcc-4.6.0

给予:

1
4 4
-1 4

我在哪里可以找到参考资料:

  1. 第一种情况是正确的(gcc-4.6 中的错误)
  2. 第二种情况是正确的(gcc
  3. 两种情况都正确,行为未定义

【问题讨论】:

  • std::remove 怎么了?

标签: c++ gcc iostream


【解决方案1】:

好吧,这不是一个错误,即使它似乎是必需的行为:

根据 C++ 2003 标准:

  • tellg(): (27.6.1.3)

    构造一个哨兵对象后,如果fail() != false,返回pos_type(-1)表示失败。否则,返回 rdbuf()->pubseekoff(0, cur, in)。

  • 哨兵(27.6.1.1.2):

    如果 noskipws 为零且 is.flags() & ios_base::skipws 为非零,则函数 只要下一个可用的输入字符 c 是空白字符,就会提取并丢弃每个字符。如果 is.rdbuf()->sbumpc() 或 is.rdbuf()->sgetc() 返回 traits::eof(),函数调用 setstate(failbit | eofbit) (可能抛出 ios_base::failure)。

基本上是这样

  • tellg() 创建哨兵对象:
  • sentry 提取空白字符,并应在到达 eof 后设置故障位。
  • tellg() 看到 failbit 应该返回 eof() (-1)

所以 gcc-4.6 似乎表现正确......

【讨论】:

    【解决方案2】:

    我可以确认差异。但是,不是编译器的区别,不是标准库头的区别,是链接共享库的区别。

    它不依赖于 gcc 版本。它不依赖于架构:

    t44:       ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
    t45:       ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
    t46:       ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
    

    真正的区别似乎是

    • 猫鼬:libstdc++6 4.5.1-7ubuntu2
    • natty: libstdc++6 4.6.0-3~ppa1(来自here

    在 ubuntu 猫鼬上

    $ uname -a
    Linux natty 2.6.38-8-generic #42-Ubuntu SMP Mon Apr 11 03:31:24 UTC 2011 i686 GNU/Linux
    $ for a in t4?; do ./$a; done
    1
    4 4
    4 4
    1
    4 4
    4 4
    1
    4 4
    4 4
    

    在 ubuntu 上运行

    Linux natty 2.6.38-8-generic #42-Ubuntu SMP Mon Apr 11 03:31:24 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
    sehe@natty:/mnt/jail/home/sehe$ for a in t4?; do ./$a; done
    1
    4 4
    -1 4
    1
    4 4
    -1 4
    1
    4 4
    -1 4
    

    【讨论】:

      【解决方案3】:

      好的,与版本分析分开,我会留下很好的衡量标准,这里是答案:

      PR/26211

      我会尝试寻找源代码,但是这个帖子讨论了是否因为这个变化而需要更新文档。因此,这是一个记录在案的更改:)

      编辑只找到这个:libstdc++/26211 (again) + N3168

      从此页面:http://gcc.gnu.org/ml/libstdc++/2011-04/msg00026.html

      大家好。

      我最近开始使用 gcc-4.6.0,似乎 当(仅)设置 eofbit 时,std::istream::tellg() 已更改。一世 设法将其追踪到 PR/26211,我不争论 变化。

      我花了一段时间才弄清楚出了什么问题,因为 doxygen 对于tellg() 说:

      If fail() is not false, returns pos_type(-1) to indicate
      failure. Otherwise returns rdbuf()->pubseekoff(0,cur,in).
      

      这几乎是朗格和克雷夫特所说的逐字逐句,所以我 假设 DR60 对 27.6.1.3 第 37 段的更改导致了这一点 libstdc++ 行为的变化。

      是否应该更新 libstdc++ doxygen 以说明 事实上,调用tellg()when eof() 也将返回pos_type(-1) (因为它构造了一个哨兵)?有没有其他 由于以下原因,也应该更新文档的功能 DR60?

      【讨论】:

      • 但是eof() 不是fail() 的一部分。状态中有三个位,eofbitbadbitfailbitfail() 仅报告是否设置了最后两个中的任何一个。 (FDIS 的 27.5.5.4/9)
      • @Bo:我想这正是重点。为什么要以but 开头?另外,请注意我没有写那个文本,它来自 GNU 开发者邮件列表
      • 我使用了“但是”,因为我看不出这是如何改变的。我相信 tellp 和 tellg 应该从底层 C 库中调用相同的 fseekpos 函数,除非 Paolo Carlini 找到了我错过的东西。
      • 问题是如果它是一个错误并且似乎是一个错误,我可以在标准中找到任何相关的内容以便我可以打开一个错误吗?
      • 链接的资源强烈表明旧行为是一个错误。我还没有找到匹配的规范。我想你能找到它。你当然可以做务实的事情,并特别检查 eof 条件,而不是依赖于你承认找不到规范的行为;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-04
      • 1970-01-01
      • 2013-05-04
      • 1970-01-01
      相关资源
      最近更新 更多