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

时间:2016-03-07 16:20:15

标签: c visual-studio fopen fgetc

当我在windows(Visual Studio 15)上构建时,在我的freeBSD系统上运行正常的程序失败了。它在这里进入无限循环:

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

仔细看(通过添加一堆fgetpos() - 调用)我发现fgetc向后移动文件位置指示符 。所以它错过了文件的开头和一些'@',如果它们不是从最后的3位数。

我注意到只有在用

打开文件f时才会发生这种情况
fopen(filename, "a+");
//text mode read/append

当我将其更改为

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

然后一切都按预期工作。 我认为对于我的代码来说,一直使用二进制模式是安全的。 但仍有两个问题:

  • 是否存在违反二元模式的原因?
  • 文字模式中的方向错误是什么诀窍?

1 个答案:

答案 0 :(得分:2)

引用 C11 7.21.9.2 fseek 功能:

  

对于文本流,偏移量应为零,或者offset应为先前成功调用与同一文件关联的流上的ftell函数返回的值,并且应为SEEK_SET。

C标准不涵盖在文本模式下打开的流上使用fseek的whence参数调用SEEK_CUR。以二进制模式打开文件似乎是一个更好的选择。

fgetpos()返回的值可能没有意义作为文件中的偏移量,它只是作为参数传递给fsetpos()

作为一般性评论,您应该尝试更改算法以避免依赖于流中的向后搜索,尤其是依赖fseek()错误似乎不可靠。而是使用fgetc()ftell()fgetpos()之前保存位置,并在需要时使用fseek(pos, SEEK_SET, fp)fsetpos()将其恢复。