c – 更改文件内容 – 这是g 4.7.2中的错误还是我做错了?

在编写一些代码来更新二进制文件中的位置时,我发现了一些奇怪的东西.考虑这个示例代码:

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    char tmp;
    string s;
    fstream fs;

    fs.open("test.txt", fstream::out);
    fs << "blub" << endl;
    fs.close();
    fs.open("test.txt", fstream::in);
    fs >> s;
    cout << s << endl;
    fs.close();

    fs.open("test.txt", ios::in|ios::out|ios::binary);
    if (!fs.is_open() || !fs.good())
        cerr << "could not open!" << endl;

    fs.read(&tmp, 1);
    fs.read(&tmp, 1);
    //fs.tellg(); //<-- required to fix for old g++?
    const char *c = "ah";
    fs.write(&c[0], 1);
    fs.write(&c[1], 1);
    fs.close();

    fs.open("test.txt", fstream::in);
    fs >> s;
    cout << s << endl;
}

在最近的g版本中(至少使用6.2.1版本),我可以只读取然后编写一些没有问题的字节 – 在示例中,您可以获得正确的输出:

blub
blah

然后我用g 4.7.2编译代码,突然更新没有效果,即第二个输出仍然是“blub”,除非我添加fs.tellg()或fs.tellp().我发现了this问题,但据我了解,这是Windows的限制,但我在Linux下工作.

现在我想知道,这是旧g中的一个错误还是我做错了,并且幸运的是现代g版本,它只是有效吗?第二个问题,为什么要求当前的位置修复它?

提前致谢!

最佳答案

Now I wonder, is this a bug in the old g++

不,在这方面没有错误.

or am I doing it wrong

是.您在链接的answer中对此进行了解释.

… output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end- of-file.

这是来自C标准,但通过以下方式提出相关:

The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf are the same as for reading and writing with the Standard C library FILEs.

有一个错误,但它在您的代码中.您的计划不符合标准规定的要求.

but as I understand, this is a limitation under Windows

可能是这种情况,但更一般地说,限制是在C(和C)规范中.标准库是否具有限制对库是否符合标准没有影响.任何依赖于不存在限制的代码都不符合标准.

and was [I] just lucky with the modern g++ version

有人可能会说你不走运.当程序不起作用而你发现了这个bug时,这是一个好运.

Second question, why does asking for the current position fix it?

我怀疑tellg足以使您的程序符合标准.所以,我会说它偶然“修复”了这个程序.

你可能应该使用std :: flush(fs);代替.

this would mean that the NEW version is LESS standard compliant?

不,这两个版本的g在这方面同样合规.你的程序不是.

点赞