A few weeks ago (August 7th, 2025) an old C program started corrupting its output file and after investigation, I found the ftell() function is no more returning the correct offset in a text file.
I replicated the issue in Linux and in Windows with the following example:
#include <stdio.h>
int main()
{
/* Opening file in read mode */
FILE *fp = fopen("g4g.txt", "r");
/* Reading first string */
char string[20];
fscanf(fp, "%s", string);
/* Printing position of file pointer */
printf("{%s}, %ld\n", string, ftell(fp));
return 0;
}
Contents of the file g4g.txt:
Someone over there is calling you. We are going for work. Take care of yourself.
I expect the output to be Someone, 7 because the word read from the file by fscanf() has 7 characters and ftell() returns a value that should allow fseek() to position the file offset just after this word.
In Linux, the output is Someone, 7 as expected, but on my Windows laptop, the output is Someone, 6. I asked a coworker to try it on his laptop and the output was Someone, 7 as expected.
The problem has been propagating slowly to other users after 1 or 2 weeks; now we are 3 to have this problem.
Here are the setups and results for Cygwin64 (gcc and mingw) and VisualStudio:
Setup
Cygwin 64 with gcc & mingw32
$ cygcheck -c cygwin; gcc -v; i686-w64-mingw32-gcc -v
Cygwin Package Information
Package Version Status
cygwin 3.6.4-1 OK
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/13/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /mnt/share/packages/gccmake/gcc-13/gcc/gcc.x86_64/src/gcc-13.4.0/configure --srcdir=/mnt/share/packages/gccmake/gcc-13/gcc/gcc.x86_64/src/gcc-13.4.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable-shared --enable-shared-libgcc --enable-static --enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit --enable-clocale=newlib --with-dwarf2 --with-tune=generic --enable-languages=ada,c,c++,fortran,lto,objc,obj-c++,jit --enable-graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable-libquadmath --enable-libquadmath-support --disable-libssp --enable-libada --disable-symvers --disable-multilib --with-gnu-ld --with-gnu-as --with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl-prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.4.0 (GCC)
Using built-in specs.
COLLECT_GCC=i686-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-w64-mingw32/13/lto-wrapper.exe
Target: i686-w64-mingw32
Configured with: /mnt/share/cygpkgs/mingw64-i686-gcc/mingw64-i686-gcc.x86_64/src/gcc-13.4.0/configure --srcdir=/mnt/share/cygpkgs/mingw64-i686-gcc/mingw64-i686-gcc.x86_64/src/gcc-13.4.0 --prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc --docdir=/usr/share/doc/mingw64-i686-gcc --htmldir=/usr/share/doc/mingw64-i686-gcc/html -C --build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=i686-w64-mingw32 --without-libiconv-prefix --without-libintl-prefix --with-sysroot=/usr/i686-w64-mingw32/sys-root --with-build-sysroot=/usr/i686-w64-mingw32/sys-root --disable-multilib --disable-win32-registry --enable-languages=c,c++,fortran,lto,objc,obj-c++ --enable-fully-dynamic-string --enable-graphite --enable-libgomp --enable-libquadmath --enable-libquadmath-support --enable-libssp --enable-version-specific-runtime-libs --with-dwarf2 --with-gnu-ld --with-gnu-as --with-gcc-major-version-only --with-tune=generic --with-cloog-include=/usr/include/cloog-isl --with-system-zlib --enable-threads=posix --libexecdir=/usr/lib
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.4.0 (GCC)
Ubuntu 24
~$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-linux-gnu/13/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:amdgcn-amdhsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 13.3.0-6ubuntu2~24.04' --with-bugurl=file:///usr/share/doc/gcc-13/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-13 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --enable-libphobos-checking=release --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-13-fG75Ri/gcc-13-13.3.0/debian/tmp-gcn/usr --enable-offload-defaulted --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --with-build-config=bootstrap-lto-lean --enable-link-serialization=2
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 13.3.0 (Ubuntu 13.3.0-6ubuntu2~24.04)
~$ uname -r
6.14.0-29-generic
First test inside Cygwin64
With gcc
gcc ftell.c
./a.exe
Result:
{Someone}, 7
With mingw32-w64-gcc
i686-w64-mingw32-gcc ftell.c
./a.exe
Result:
{Someone}, 6
With Visual Studio 2022
>"c:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\Hostx86\x64\cl.exe" /TC ftell.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35215 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
ftell.c
Microsoft (R) Incremental Linker Version 14.44.35215.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:ftell.exe
ftell.obj
>ftell.exe
{Someone}, 6
Ubuntu 24
gcc ftell.c
./a.out
Result:
{Someone}, 7
The ftell function was not designed to return the actual offset from text files.
Section 7.21.9.4p2 of the C11 standard regarding the ftell function states:
For a text stream, its file position indicator contains unspecified information, usable by the
fseekfunction for returning the file position indicator for the stream to its position at the time of theftellcall; the difference between two such return values is not necessarily a meaningful measure of the number of characters written or read.
Additionally, the Microsoft documentation for ftell states:
The value returned by
ftelland_ftelli64may not reflect the physical byte offset for streams opened in text mode, because text mode causes carriage return-line feed translation. Useftellwithfseekor_ftelli64with_fseeki64to return to file locations correctly.
What this means is that if you're using ftell for anything other that passing to fseek, you can't expect any particular result.
A common (but incorrect) usage of ftell is to determine the size of a file. The proper way to do this is with the stat function on Linux or the _stat or _stat64 functions on Windows.
struct stat finfo;
stat("g4g.txt", &finfo);
printf("size=%jd\n", (intmax_t)finfo->st_size);