为什么 ftell 的 return 类型不是 fpos_t?

Why is the return type for ftell not fpos_t?

根据 C99,ftell 的原型是:

long int ftell(FILE *stream);

根据我的理解,应该是以下内容:

fpos_t ftell(FILE *stream);

这是为什么?

来自§7.19.1-2

fpos_t which is an object type other than an array type capable of recording all the information needed to specify uniquely every position within a file.

我明白 fpos_t 应该用来记录文件中的位置。因此 ftell 文件中的哪个 returns 位置应该属于该类型。相反,它是:

来自 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.

ftell() 需要 return 文件指针在文件中的偏移量。这些是完全不同的接口。

注意 fpos_t

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

所以它甚至可以是一个结构,除了调用 fsetpos 之外完全不能用于任何其他用途!

另一方面,ftell 的 return 值是一个标量,保证可用于告知二进制文件中的确切字节位置:

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


除此之外,原因是向后兼容性ftell 在 C89 中首次亮相,也许当时的期望是 long 可以足够快地扩展以包含所有文件大小,但如今情况并非总是如此。不幸的是,无法更改由 ftell 编辑的 return 类型,但现在更改它为时已晚 - 即使那些支持更大文件的平台现在也有另一个名称的函数,例如 ftello.


需要签名,因为函数 returns -1 出错。

最可能的用途是允许错误 return 值为负数。它与 printf 函数族相同,即 return ssize_t 而不是 size_t,恰好是 size_tsigned 版本.

这些技巧中的第一个发生在 getchar() 上,return 是 int 而不是 char,以允许值 returned on文件结束条件 (EOF) 通常是一个负值,以与整组可能的 returned 字符(在 0255 范围内,所有正整数)

为什么不定义相同类型的签名扩展以允许 -1?其实不知道:)

历史原因。

fseekftell 是非常古老的函数,早于 C 标准化。他们假设 long 足够大以表示任何文件中的一个位置——这个假设在当时可能是有效的。 long 至少是 32 位,并且 显然 单个文件不能超过 2 GB(甚至 1.21 gigabytes)。

当第一个 C 标准发布时(ANSI C,1989),很明显这个假设不再有效,但是改变 fseekftell 的定义会破坏了现有的代码。此外,仍然没有比 long 宽的整数类型(long long 直到 C99 才被引入)。

ANSI C 委员会决定 fseekftell 仍然有用,但他们引入了新的文件定位函数 fsetposfgetpos。这些函数使用不透明的非数字类型 fpos_t 而不是 long,这使得它们比 fseekftell 更灵活也更不灵活。一个实现可以定义 fpos_t 因此它可以表示任何可能的文件偏移量——但由于它是非数字类型,fsetposfgetpos 不提供 SEEK_SET / SEEK_CUR / SEEK_END 特征。例如,无法使用 fsetpos 将文件定位到末尾。

其中一些在 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.

如果今天从头开始定义它,可能会有一对函数涵盖当前四个函数的所有功能,很可能使用需要足够大的 typedefed 整数类型表示任何可能的文件偏移量。 (对于当前的系统,64 位可能就足够了,但在大型系统上不久之后看到 8 艾字节的文件我不会感到惊讶)。