ftell在2GB以上的位置

问题描述 投票:10回答:4

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

c file-io c99 stdio ftell
4个回答
12
投票

在长int

long int 应该是至少32位的,但C99标准并没有限制它为32位。C99标准确实提供了方便类型,比如 int16_t & int32_t 等,映射到目标平台的正确比特大小。

在ftellfseek

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

POSIX.1-2001和SysV函数,对于 fseekftellfseekoftello 因为它们使用 off_t 作为偏移量的参数。

你确实需要用 -D_FILE_OFFSET_BITS=64 或在包含stdio.h之前在某个地方定义它,以确保 off_t 是64位的。

阅读关于这一点在 cert.org安全编码指南.

关于长int的ftell和大小的混淆。

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;
}

注意 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'


6
投票

至少在32位操作系统上 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标准1003.1,2013年版 ftell() 将返回 -1 并设置 errnoEOVERFLOW 在这种情况下。

EOVERFLOW

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


3
投票

在C99标准中没有64b感知方法。你使用的是什么OSenvironment?在windows系统中,有一个 _ftelli64.

在其他平台上,看看 http:/forums.codeguru.comshowthread.php?277234-Cannot-use-fopen()-open-file-larger-than-4B。


0
投票

这对我来说,在Windows32MinGW上玩6GB的文件是有效的。

#define _FILE_OFFSET_BITS 64
#include<stdio.h>

int main() {
    FILE *f = fopen("largefile.zip","rb");
    fseeko64(f, 0, SEEK_END);
    off64_t size = ftello64(f);

    printf("%llu\n", size);
}

gcc readlargefile.c -c -std=C99 -o readlargefile.exe

每一个细节,宏,编译器选项,都很重要。

© www.soinside.com 2019 - 2024. All rights reserved.