Why is the return type for ftell not fpos_t?

Notice that fpos_t is

[...] a complete object type other than an array type capable of recording all the information needed to specify uniquely every position within a file.

So it can can be even a structure, totally unusable for anything else besides calling fsetpos!

On the other hand the return value of ftell is a scalar which is guaranteed to be possible to use in telling the exact byte position in a binary file:

For a binary stream, the value is the number of characters from the beginning of the file.


Other than that, the reason is backwards-compatibility. ftell debuted in C89, and perhaps then the expectation was that long would scale fast enough to contain all file sizes, something that is not always true nowadays. Unfortunately it is not possible to change the type returned by ftell but it is too late to change that now - even those platforms that support larger files now have functions with another name, such as ftello.


the signedness is required because the function returns -1 on error.


Historical reasons.

fseek and ftell are very old functions, predating C standardization. They assume that long is big enough to represent a position in any file -- an assumption that was probably valid at the time. long is at least 32 bits, and obviously you couldn't have a single file bigger than 2 gigabytes (or even 1.21 gigabytes).

By the time the first C standard was published (ANSI C, 1989), it was becoming obvious that this assumption was no longer valid, but changing the definitions of fseek and ftell would have broken existing code. Furthermore, there was still no integer type wider than long (long long wasn't introduced until C99).

The ANSI C committee decided that fseek and ftell were still useful, but they introduced new file positioning functions fsetpos and fgetpos. These functions use an opaque non-numeric type fpos_t rather than long, which makes them both more and less flexible than fseek and ftell. An implementation can define fpos_t so it can represent any possible file offset -- but since it's a non-numeric type, fsetpos and fgetpos don't provide the SEEK_SET / SEEK_CUR / SEEK_END feature. For example, there's no way to use fsetpos to position a file to its end.

Some of this is addressed in the ANSI C Rationale, section 4.9.9:

Given these restrictions, the Committee still felt that this function [fseek] has enough utility, and is used in sufficient existing code, to warrant its retention in the Standard. fgetpos and fsetpos have been added to deal with files which are too large to handle with fseek and ftell.

If this were being defined from scratch today, there would probably be a single pair of functions covering all the functionality of the current four functions, likely using a typedefed integer type required to be big enough to represent any possible file offset. (With current systems, 64 bits is likely to be sufficient, but I wouldn't be surprised to see 8-exabyte files before too long on large systems).


From the manpage of fgetpos()/fsetpos():

On some non-UNIX systems, an fpos_t object may be a complex object and these routines may be the only way to portably reposition a text stream.

whereas ftell() is required to return the offset of the file pointer in the file. These are completely different interfaces.

Tags:

C

C99