Compilando para acesso a arquivos de 64 bits

1

Eu revisei várias respostas para compilar código para torná-lo a ler / gravar arquivos além do máximo de 4 GB permitido pelos deslocamentos de arquivo de 32 bits. Não estou tendo sorte com nenhuma das soluções "simples" que estou encontrando.

A essência é que tenho o Ubuntu Server 11.10 rodando em um pequeno laptop (arquitetura Intel de 32 bits). Eu estou tentando ler um arquivo unicode que é 343868522737 bytes em tamanho (0x50102940f1). A máquina do Ubuntu continua pensando que é muito menor (0x102940f1), que acaba sendo apenas os 32 bits mais baixos de um arquivo com tamanho de 64 bits.

Eu escrevi um pequeno programa que eu compilei em um MacOS e na caixa do Ubuntu. O Mac parece se comportar corretamente, a caixa do Ubuntu não funciona.

O pequeno programa está abaixo. Embora tenha comentado um bloco de código, isso é realmente necessário apenas para o Mac. O ambiente Ubuntu compilará ambos os blocos de código - e gerará exatamente a mesma resposta para ambos os blocos.

// 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, '
// 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, '%pre%', 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");
    }
}
', 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"); } }

Salve o trecho como file_test.c, então a compilação é muito simples.

gcc file_test.c

Em seguida, execute o a.out

Alguma sugestão para obter este código para reconhecer arquivos além do limite de 32 bits? Neste ponto, estou simplesmente perplexo.

    
por dwmc 12.01.2012 / 08:01

2 respostas

3

De acordo com o presente , o tamanho de long unsigned int no Unix de 32 bits é de 4 bytes - pode ser que o valor seja aparado onde você está enviando fmaxlen para (long unsigned int)?

    
por Sergey 12.01.2012 / 08:24
1

Você pode encontrar documentação para as macros que controlam esse comportamento com man feature_test_macros .

A partir dessa documentação, você só precisa definir _FILE_OFFSET_BITS para 64 . Isso deve redefinir off_t e funções como fseeko , ftello para versões seguras de 64 bits (isso é um não operacional em sistemas de 64 bits e redireciona os símbolos para as versões com sufixo 64 em 32 bits sistemas). Isso é preferível ao uso das funções 64 com sufixo diretamente.

E, como disse Sergey, converter o valor off_t para long unsigned int perderá informações em sistemas de 32 bits. Não creio que exista um código de formato printf padrão para off_t , portanto, é melhor que você converta o valor para unsigned long long int e use o %#llx como o código de formato. Isso deve estar livre de aviso em ambos os tamanhos de palavras e não perder informações.

    
por James Henstridge 12.01.2012 / 11:16