简体   繁体   English

为什么fgetc向后移动文件位置指示器?

[英]Why does fgetc move the file position indicator backwards?

A program that runs just fine on my freeBSD system fails when I build it on windows (Visual Studio 15). 当我在Windows(Visual Studio 15)上构建时,在freeBSD系统上运行良好的程序失败。 It goes into an endless loop here: 它在这里陷入无尽的循环:

//...
while (1) {
    if ('@' == fgetc(f)) {
        // we do some stuff here. irrelevant for stackoverflow question
        break;
    }        
    fseek(f, -1, SEEK_CUR);        
    if (0 != fseek(f, -1, SEEK_CUR)) {
        // Beginning of file.
        break;
    }
}
//...

On closer look (by adding a bunch of fgetpos()-calls) I find that fgetc moves the file position indicator backwards . 仔细观察(通过添加一堆fgetpos()调用),我发现fgetc 向后移动文件位置指示器。 So it misses the beginning of the file and some '@' if they are not in a multiple-of-3 position from the end. 因此,它会错过文件的开头,如果它们与末尾的位置不是3的倍数,则会丢失一些“ @”。

I notice that this only happenes when the file f is opened with 我注意到这仅在使用以下文件f打开时发生

fopen(filename, "a+");
//text mode read/append

When I change it to 当我将其更改为

fopen(filename, "ab+");
//binary mode read/append

then everything works as expected. 然后一切都会按预期进行。 I think for my code it is safe just to use binary mode all the time. 我认为对于我的代码而言,始终使用二进制模式是安全的。 But two questions remain: 但是仍然存在两个问题:

  • Are there reasons that stand against binary mode? 有什么理由反对二进制模式吗?
  • What trickery is this with wrong direction in text mode? 在文本模式下方向错误这是什么技巧?

Quoting C11 7.21.9.2 the fseek function: 引用C11 7.21.9.2fseek函数:

For a text stream, either offset shall be zero, or offset shall be a value returned by an earlier successful call to the ftell function on a stream associated with the same file and whence shall be SEEK_SET. 对于文本流,offset应该为零,或者offset应该是对与同一文件相关联的流上的ftell函数的较早成功调用返回的值,并且whence应该为SEEK_SET。

Invoking fseek with a whence argument of SEEK_CUR on a stream open in text mode is not covered by the C Standard. C标准不包括在文本模式下打开的流上使用SEEK_CUR的whence参数调用fseek Opening the file in binary mode seems a much better option. 以二进制模式打开文件似乎是一个更好的选择。

The value returned by fgetpos() may not be meaningful as an offset in the file, it is only meant to be passed as an argument to fsetpos() . fgetpos()返回的值作为文件中的偏移量可能没有意义,它仅应作为参数传递给fsetpos()

As a general remark, you should try and change you algorithms to avoid relying on backwards seeks in the stream, especially relying on fseek() errors seems unreliable. 通常,您应该尝试更改算法,以避免依赖于流中的向后搜索,尤其是依赖fseek()错误似乎不可靠。 Instead save the position before the fgetc() with ftell() or fgetpos() and restore it when needed with fseek(pos, SEEK_SET, fp) or fsetpos() . 而是使用ftell()fgetpos()将位置保存在fgetc()之前,并在需要时使用fseek(pos, SEEK_SET, fp)fsetpos()恢复该位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM