Domanda

Sto tentando di scrivere un'estensione Python C che legge i dati binari compressi (è archiviato come strutture di strutture) e quindi li analizza in oggetti Python. Tutto funziona come previsto su una macchina a 32 bit (i file binari sono sempre scritti su un'architettura a 32 bit), ma non su una scatola a 64 bit. C'è un & Quot; preferito & Quot; modo di farlo?


Sarebbe molto codice da pubblicare ma come esempio:

struct
{
    WORD    version;
    BOOL    upgrade;
    time_t  time1;
            time_t  time2;
} apparms;

File *fp;
fp = fopen(filePath, "r+b");
fread(&apparms, sizeof(apparms), 1, fp);
return Py_BuildValue("{s:i,s:l,s:l}",
  "sysVersion",apparms.version,
  "powerFailTime", apparms.time1,
  "normKitExpDate", apparms.time2
 );

Ora su un sistema a 32 bit funziona alla grande, ma su un 64 bit le dimensioni del mio time_t sono diverse (32 bit contro 64 bit).


Accidenti, voi gente siete veloci.

Patrick, inizialmente ho iniziato a usare il pacchetto struct ma ho trovato il modo giusto di rallentare per le mie esigenze. Inoltre stavo cercando una scusa per scrivere un'estensione Python.

So che questa è una domanda stupida, ma a quali tipi devo fare attenzione?

Grazie.

È stato utile?

Soluzione

Specifica esplicitamente che i tuoi tipi di dati (es. numeri interi) sono a 32 bit. Altrimenti se hai due numeri uno accanto all'altro quando li leggi, verranno letti come un numero intero a 64 bit.

Quando hai a che fare con problemi multipiattaforma, le due cose principali a cui prestare attenzione sono:

  1. bitness. Se i tuoi dati compressi sono scritti con ints a 32 bit, tutto il tuo codice deve specificare esplicitamente ints a 32 bit durante la lettura di e .
  2. Ordine byte. Se si sposta il codice dai chip Intel a PPC o SPARC, l'ordine dei byte sarà errato. Dovrai importare i tuoi dati e poi capovolgerli in modo che corrispondano all'architettura corrente. Altrimenti 12 (0x0000000C) verrà letto come 201326592 (0x0C000000).

Speriamo che questo aiuti.

Altri suggerimenti

Il modulo 'struct' dovrebbe essere in grado di farlo, sebbene l'allineamento delle strutture nel mezzo dei dati sia sempre un problema. Non è molto difficile farlo bene, tuttavia: scopri (una volta) a quale confine si allineano le strutture in, quindi passa (manualmente, con l'identificatore 'x') a quel limite. Puoi ricontrollare la tua imbottitura confrontando struct.calcsize () con i tuoi dati reali. È certamente più facile che scrivere un'estensione C per questo.

Per continuare a usare Py_BuildValue () in questo modo, hai due opzioni. È possibile determinare la dimensione di time_t in fase di compilazione (in termini di tipi fondamentali, quindi 'an int' o 'a long' o 'an ssize_t') e quindi utilizzare il carattere di formato corretto per Py_BuildValue - 'i' per un int, 'l' per un lungo, 'n' per un ssize_t. Oppure puoi usare PyInt_FromSsize_t () manualmente, nel qual caso il compilatore esegue l'upcasting per te, quindi usa i caratteri in formato 'O' per passare il risultato a Py_BuildValue.

Devi assicurarti di utilizzare membri indipendenti dall'architettura per la tua struttura. Ad esempio un int può essere 32 bit su un'architettura e 64 bit su un'altra. Come altri hanno suggerito, utilizzare invece i tipi di stile int32_t. Se la struttura contiene membri non allineati, potrebbe essere necessario gestire anche il riempimento aggiunto dal compilatore.

Un altro problema comune con i dati di architettura incrociata è l'endianità. L'architettura Intel i386 è un po 'endian, ma se stai leggendo su una macchina completamente diversa (ad esempio un Alpha o Sparc), dovrai preoccuparti anche di questo.

Il modulo Python struct affronta entrambe queste situazioni, usando il prefisso passato come parte della stringa di formato.

  • @: utilizza dimensioni, endianness e allineamento nativi. i = sizeof (int), l = sizeof (long)
  • = - Usa endianness nativo, ma dimensioni e allineamento standard (i = 32 bit, l = 64 bit)
  • lt &; - Dimensioni / allineamento standard little-endian
  •   
        
    • Dimensioni / allineamento standard big-endian
    •   

In generale, se i dati passano dal tuo computer, dovresti inchiodare l'endianness e il formato dimensione / riempimento a qualcosa di specifico & # 8212; vale a dire. usa " < " oppure " > " come il tuo formato. Se vuoi gestirlo nella tua estensione C, potresti dover aggiungere del codice per gestirlo.

Qual è il tuo codice per leggere i dati binari? Assicurati di copiare i dati in tipi di dimensioni adeguate come int32_t anziché solo int.

Perché non stai usando il pacchetto struct ?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top