当我在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
然后一切都按预期工作。 我认为对于我的代码来说,一直使用二进制模式是安全的。 但仍有两个问题:
答案 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()
将其恢复。