ftell在2GB以上的位置
在32位系统上,如果以二进制模式打开的文件的当前位置指示符超过2GB点, ftell
返回什么? 在C99标准中,这是未定义的行为,因为ftell
必须返回一个long int
(最大值为2**31-1
)?
在long int
long int
应该是至少32位,但C99标准不限制为32位。 C99标准确实提供了诸如int16_t
和int32_t
等便利类型,它们映射到目标平台的正确位大小。
在ftell / fseek
在绝大多数32位架构系统中, ftell()
和fseek()
限制为32位(包括符号位)。 所以当有大量文件支持时,你会遇到这个2GB的问题。
用于fseek
和ftell
POSIX.1-2001和SysV函数是fseeko
和ftello
因为它们使用off_t作为偏移量的参数。
你需要用-D_FILE_OFFSET_BITS=64
定义编译,或者在包含stdio.h之前在某处定义编译,以确保off_t
是64位。
请阅读cert.org安全编码指南,了解相关信息。
关于long int的ftell和size的混淆
C99表示long int
必须至少为 32位,并不表示它不能更大
在x86_64架构上尝试以下操作:
#include int main(int argc, char *argv[]) { FILE *fp; fp = fopen( "test.out", "w"); if ( !fp ) return -1; fseek(fp, (1L << 34), SEEK_SET); fprintf(fp, "\nhello world\n"); fclose(fp); return 0; }
请注意, 1L
只是一个long
,这将生成一个17GB的文件,并在其末尾"\nhello world\n"
一个"\nhello world\n"
。 您可以通过使用tail -n1 test.out
或明确使用以下内容来validation:
dd if = test.out skip = $((1 << 25))
请注意,dd通常使用块大小(1 << 9)
因此34 - 9 = 25
将转出'\nhello world\n'
至少在32位OS ftell()
它会溢出或出错或者只是遇到未定义的行为。
为了解决这个问题,你可能想使用off_t ftello(FILE *stream);
和#define _FILE_OFFSET_BITS 64
。
从man ftello
逐字:
fseeko()和ftello()函数分别与fseek(3)和ftell(3)(参见fseek(3))相同,除了fseeko()的偏移参数和ftello()的返回值是输入off_t而不是long。
在许多体系结构中,off_t和long都是32位类型,但编译时使用
#define _FILE_OFFSET_BITS 64
将off_t关闭为64位类型。
更新:
根据IEEE Std 1003.1,2013版 ftell()
应返回-1
并在这种情况下将errno
为EOVERFLOW
:
EOVERFLOW
对于ftell(),当前文件偏移量无法在long类型的对象中正确表示。
C99标准中没有64b识别方法。 您使用的操作系统/环境是什么? 在Windows上,有_ftelli64
。
在其他平台上,请查看http://forums.codeguru.com/showthread.php?277234-Cannot-use-fopen()-open-file-larger-than-4-GB