在我的 freeBSD 系统上运行良好的程序在 Windows (Visual Studio 15) 上构建时失败。它在这里进入无限循环:
//...
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
然后一切都按预期工作。 我认为对于我的代码来说,一直使用二进制模式是安全的。 但是还有两个问题:
- 是否有反对二进制模式的理由?
- 在文本模式下方向错误是什么诡计?
最佳答案
引用 C11 7.21.9.2 fseek
函数:
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.
在以文本模式打开的流上使用 SEEK_CUR
的 whence 参数调用 fseek
未包含在 C 标准中。以二进制模式打开文件似乎是一个更好的选择。
fgetpos()
返回的值作为文件中的偏移量可能没有意义,它只是作为参数传递给 fsetpos()
。
作为一般性评论,您应该尝试更改算法以避免依赖流中的向后查找,尤其是依赖 fseek()
错误似乎不可靠。而是使用 ftell()
或 fgetpos()
保存 fgetc()
之前的位置,并在需要时使用 fseek(pos , SEEK_SET, fp)
或 fsetpos()
。
关于c - 为什么 fgetc 将文件位置指示器向后移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35848744/