Turns out there are quite a few functions defined by various standards:
fseek/ftell
It's defined by ANSI standard library. It's available virtually everywhere. It is guaranteed to work with 32-bit integers only, but it isn't required to (meaning you might get support for large files out of the box).
fseeko/ftello
This is defined by POSIX standard. On many platforms, depending on value of _FILE_OFFSET_BITS it will cause off_t to be defined as off64_t and fseeko as fseeko64 for _FILE_OFFSET_BITS=64.
fseeko64/ftello64
This is the 64-bit equivalent of fseeko and ftello. I couldn't find information on this in any standard.
Cygwin inconsistency
While it conforms to POSIX, I can't compile the fseeko no matter what I define under Cygwin, unless I use --std=gnu++11 which is obviously nonsense, since it's part of POSIX rather than a GNU extension. So what gives? According to this discussion:
64 bit file access is the natural
file access type for Cygwin. off_t is 8 bytes. There are no foo64
functions for that reason. Just use fopen and friends and you get 64
bit file access for free.
This means #ifdef for cygwin on POSIX platforms.
_fseeki64 / _ftelli64
These are defined by Microsoft Visual C++ and are exclusively used with their compiler. Obviously it doesn't support anything else from the list above (other than fseek), so you're going to need #ifdefs.
Defined by POSIX, these are to be used with integer file descriptors opened with open() from unistd.h rather than FILE* structs. These are not compatible with Windows. Again, they use off_t data type.
_lseek, _lseeki64
This is Windows equivalent of lseek/lseek64. Curiously, _lseeki64 doesn't use off_t and uses __int64 instead, so you know it'll work with big files. Neat.
fsetpos/fgetpos
While these are actually pretty portable, they're almost unusable, since they operate on opaque structures rather than integer offsets, meaning you can add or subtract them, or even navigate to certain position in file obtained by any means other than through fgetpos.
Conclusion
So to make your program portable, depending on the platform, you should use:
fseeko (POSIX) + define _FILE_OFFSET_BITS=64 on POSIX
fseek for Cygwin and for default implementation
_lseeki64 for Windows - or, if you manage to work your way around it - _fseeki64.
In reality, instead of checking #ifdefs which always looked fragile to me, you could check if the functions compile using your build systems, and define your own constants such as HAVE_FTELLO64 accordingly.
Note that if you indeed decide to use lseek/_lseeki64 family and numeric file descriptors rather than the FILE* structures, you should be aware of following differences between open/fopen:
open doesn't use buffering, fopen does. Less buffering means worse performance.
open can't perform newline conversions for text files, fopen can.
Turns out there are quite a few functions defined by various standards:
fseek
/ftell
It's defined by ANSI standard library. It's available virtually everywhere. It is guaranteed to work with 32-bit integers only, but it isn't required to (meaning you might get support for large files out of the box).
fseeko
/ftello
This is defined by POSIX standard. On many platforms, depending on value of
_FILE_OFFSET_BITS
it will causeoff_t
to be defined asoff64_t
andfseeko
asfseeko64
for_FILE_OFFSET_BITS=64
.fseeko64
/ftello64
This is the 64-bit equivalent of
fseeko
andftello
. I couldn't find information on this in any standard.Cygwin inconsistency
While it conforms to POSIX, I can't compile the
fseeko
no matter what I define under Cygwin, unless I use--std=gnu++11
which is obviously nonsense, since it's part of POSIX rather than a GNU extension. So what gives? According to this discussion:This means
#ifdef
for cygwin on POSIX platforms._fseeki64
/_ftelli64
These are defined by Microsoft Visual C++ and are exclusively used with their compiler. Obviously it doesn't support anything else from the list above (other than
fseek
), so you're going to need#ifdef
s.EDIT: I actually advise against using them and I'm not the only one who thinks that. I experienced literally following:
wfopen
a file in binary modefwrite
10 bytes worth to it_ftelli64
the positionLooks like this is horribly broken.
lseek
andlseek64
Defined by POSIX, these are to be used with integer file descriptors opened with
open()
fromunistd.h
rather thanFILE*
structs. These are not compatible with Windows. Again, they useoff_t
data type._lseek
,_lseeki64
This is Windows equivalent of
lseek
/lseek64
. Curiously,_lseeki64
doesn't useoff_t
and uses__int64
instead, so you know it'll work with big files. Neat.fsetpos
/fgetpos
While these are actually pretty portable, they're almost unusable, since they operate on opaque structures rather than integer offsets, meaning you can add or subtract them, or even navigate to certain position in file obtained by any means other than through
fgetpos
.Conclusion
So to make your program portable, depending on the platform, you should use:
fseeko
(POSIX) + define_FILE_OFFSET_BITS=64
on POSIXfseek
for Cygwin and for default implementation_lseeki64
for Windows - or, if you manage to work your way around it -_fseeki64
.An example that uses
_ftelli64
:In reality, instead of checking
#ifdef
s which always looked fragile to me, you could check if the functions compile using your build systems, and define your own constants such asHAVE_FTELLO64
accordingly.Note that if you indeed decide to use
lseek
/_lseeki64
family and numeric file descriptors rather than theFILE*
structures, you should be aware of following differences betweenopen
/fopen
:open
doesn't use buffering,fopen
does. Less buffering means worse performance.open
can't perform newline conversions for text files,fopen
can.More details in this question.
References: