针对 64 位文件访问进行编译

针对 64 位文件访问进行编译

我查看了许多关于编译代码以使其读取/写入超过 32 位文件偏移允许的 4GB 最大值的文件的答案。我找到的任何“简单”解决方案都没有成功。

要点是,我在一台小型笔记本电脑(32 位 Intel 架构)上运行 Ubuntu Server 11.10。我试图读取一个大小为 343868522737 字节(0x50102940f1)的 unicode 文件。Ubuntu 机器一直认为它要小得多(0x102940f1),结果发现它只是真正 64 位大小文件的低 32 位。

我写了一个小程序,在 MacOS 和 Ubuntu 机器上编译过。Mac 似乎运行正常,但 Ubuntu 机器则不行。

下面是一个小程序。虽然我注释掉了一个代码块,但这实际上只对 Mac 是必要的。Ubuntu 环境将很好地编译这两个代码块 - 并为这两个代码块生成完全相同的响应。

// Necessary for Ubuntu build?
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
//#include <features.h>
// finish Ubuntu

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>

// Ubuntu version
off64_t fileMaxLen(FILE* fin) {
    off64_t fmaxlen = 0;
    if( (fin!=NULL) && (fseeko64(fin,0,SEEK_END) == 0) ) {
        fmaxlen = ftello64(fin);
        fprintf(stdout,"fileMaxLen(): file length is: %#lx \n",(long unsigned int)fmaxlen);
        fseeko64(fin,0,SEEK_SET);
    }
}

// Mac OS version
//off_t fileMaxLen(FILE* fin) {
//    off_t fmaxlen = 0;
//    if( (fin!=NULL) && (fseeko(fin,0,SEEK_END) == 0) ) {
//        fmaxlen = ftello(fin);
//        fprintf(stdout,"fileMaxLen(): file length is: %#lx \n",(long unsigned int)fmaxlen);
//        fseeko(fin,0,SEEK_SET);
//    }
//}

main(int argc, char* argv[]) {
    char fname[255];
    char *locale;
    FILE* f = NULL;

    locale = setlocale(LC_ALL, "");

    if( argc>=2 ) {
        // get the file for segmenting
        memset(fname, '\0', 255);
        sprintf(fname,"%s",argv[1]);
        fprintf(stdout,"Opening: %s\n",fname);
        f = fopen(fname,"r");
        fileMaxLen(f);
        fprintf(stdout,"Done!\n");
    } else {
        fprintf(stdout,"Need a filename\n");
    }
}

将代码片段保存为file_test.c,然后编译就非常简单了。

gcc文件_测试.c

然后运行 ​​a.out

有什么建议可以让这段代码识别 32 位边界以外的文件吗?目前我完全不知所措。

答案1

根据,在32位Unix上的大小long unsigned int是4个字节-是否可以在将fmaxlen转换为(long unsigned int)时修剪该值?

答案2

您可以找到有关使用 控制此行为的宏的文档man feature_test_macros

从该文档中,您只需要设置_FILE_OFFSET_BITS64。这应该将off_t和函数(如)fseeko重新定义ftello为 64 位安全版本(这在 64 位系统上是无操作,并将符号重定向到32 位系统上的后缀版本)。这比直接64使用后缀函数更好。64

正如 Sergey 所说,将值转换off_tlong unsigned int会丢失 32 位系统上的信息。我认为 没有 的标准printf格式代码off_t,因此最好将值转换为unsigned long long int并使用%#llx作为格式代码。这应该不会对两个字长发出警告,也不会丢失信息。

相关内容