This problem is caused by libstdc ++, using the difference between the current remaining buffer with lseek64 to determine the current offset.
The buffer is set using the read return value, which for the text mode file in windows returns the number of bytes that were buffered after converting the final string (i.e., converting 2 bytes \r\n to \n , windows also seem to add false new line at the end of the file).
lseek64 however (which with mingw causes _lseeki64 to be _lseeki64 ) returns the current position of the absolute file, and after subtracting the two values, you get an offset that is disabled by 1 for each remaining new line in the text file (+1 for an extra line break line).
The following code should display a problem, you can even use a file with one character and without a new line due to the extra line inserted by the windows.
#include <iostream> #include <fstream> int main() { std::ifstream f("myfile.txt"); for (char c; f.get(c);) std::cout << f.tellg() << ' '; }
For a file with a single character a I get the following output
2 3
Clearly disable by 1 for the first call to tellg . After the second call, the file position is correct, since the end was reached after taking into account the additional line.
In addition to opening the file in binary mode, you can work around the problem by disabling buffering.
#include <iostream> #include <fstream> int main() { std::ifstream f; f.rdbuf()->pubsetbuf(nullptr, 0); f.open("myfile.txt"); for (char c; f.get(c);) std::cout << f.tellg() << ' '; }
but this is far from ideal.
Hope mingw / mingw-w64 or gcc can fix this, but first we need to determine who will be responsible for fixing it. I believe that the main problem is with the MS lysek implementation, which should return the appropriate values ββaccording to how the file was opened.