13

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

4

4 回答 4

15

长整数

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

在 ftell/fseek 上

ftell()并且fseek()在绝大多数 32 位架构系统上仅限于 32 位(包括符号位)。因此,当有大文件支持时,您会遇到这个 2GB 的问题。

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

您确实需要-D_FILE_OFFSET_BITS=64 在包含 stdio.h 之前定义 compile with 或在某处定义它以确保它off_t是 64 位的。

cert.org 安全编码指南中阅读有关此内容的信息。

关于 ftell 和 long int 大小的混淆

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只是 a long,这将生成一个 17GB 的文件并将 a 粘贴"\nhello world\n"到它的末尾。您可以通过简单地使用tail -n1 test.out或显式使用来验证是否存在:

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

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

于 2013-05-22T16:04:39.940 回答
6

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

为了解决这个问题,您可能喜欢使用off_t ftello(FILE *stream);and #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

溢出

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

于 2013-05-22T15:56:29.420 回答
3

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

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

于 2013-05-22T15:56:05.647 回答
1

这适用于我在 Windows32/MinGW 上玩 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

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

于 2020-05-31T10:39:39.240 回答