A program that runs just fine on my freeBSD system fails when I build it on windows (Visual Studio 15). 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. So it misses the beginning of the file and some '@' if they are not in a multiple-of-3 position from the end.
I notice that this only happenes when the file f is opened with
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:
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.
Invoking fseek
with a whence argument of SEEK_CUR
on a stream open in text mode is not covered by the C Standard. 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()
.
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. Instead save the position before the fgetc()
with ftell()
or fgetpos()
and restore it when needed with fseek(pos, SEEK_SET, fp)
or fsetpos()
.