ftell在2GB以上的位置

在32位系统上,如果以二进制模式打开的文件的当前位置指示符超过2GB点, ftell返回什么? 在C99标准中,这是未定义的行为,因为ftell必须返回一个long int (最大值为2**31-1 )?

在long int

long int应该是至少32位,但C99标准不限制为32位。 C99标准确实提供了诸如int16_tint32_t等便利类型,它们映射到目标平台的正确位大小。

在ftell / fseek

在绝大多数32位架构系统中, ftell()fseek()限制为32位(包括符号位)。 所以当有大量文件支持时,你会遇到这个2GB的问题。

用于fseekftell POSIX.1-2001和SysV函数是fseekoftello因为它们使用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并在这种情况下将errnoEOVERFLOW

EOVERFLOW

对于ftell(),当前文件偏移量无法在long类型的对象中正确表示。

C99标准中没有64b识别方法。 您使用的操作系统/环境是什么? 在Windows上,有_ftelli64

在其他平台上,请查看http://forums.codeguru.com/showthread.php?277234-Cannot-use-fopen()-open-file-larger-than-4-GB