[英]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:
但是仍然存在两个问题:
Quoting C11 7.21.9.2 the fseek
function: 引用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.
对于文本流,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.