ftell在2GB以上的位置

Vil*_*ray 9 c file-io stdio c99 ftell

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

Ahm*_*sud 11

在long int

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

在ftell/fseek

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

POSIX.1-2001和SysV功能fseekftellfseekoftello,因为他们使用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 <stdio.h>

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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这1L只是一个long,这将产生一个17GB的文件,并坚持"\nhello world\n"到它的结尾.您可以通过简单地使用tail -n1 test.out或明确使用来验证:

dd if = test.out skip = $((1 << 25))

请注意,dd通常使用块大小,(1 << 9)因此 34 - 9 = 25将转储出来'\nhello world\n'

  • 并非所有“x86_64”架构都以这种方式工作。具体来说,long 在 64 位 Windows 上的大小仍然是 32 位。 (2认同)

alk*_*alk 5

至少在32位操作系统上,ftell()它会溢出或出错,或者仅会遇到未定义的行为。

为了解决这个问题,您可能想使用off_t ftello(FILE *stream);#define _FILE_OFFSET_BITS 64

逐字记录来自man ftello

fseeko()和ftello()函数分别与fseek(3)和ftell(3)相同(请参阅fseek(3)),除了fseeko()的offset参数和ftello()的返回值是输入off_t而不是long。

在许多架构上,off_t和long都是32位类型,但是使用

   #define _FILE_OFFSET_BITS 64
Run Code Online (Sandbox Code Playgroud)

将把off_t变成64位类型。


更新:

根据IEEE Std 1003.1,2013版 ftell()应在以下情况下返回-1并设置errnoEOVERFLOW

人流

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