2010-09-29 9 views
15

Mi sono guardato attorno su come convertire big-endian in little-endian. Ma non ho trovato nulla che potesse risolvere il mio problema. Sembra che ci sia un modo in cui puoi fare questa conversione. Comunque questo codice seguente funziona bene in un sistema big-endian. Ma come dovrei scrivere una funzione di conversione in modo che funzioni anche sul sistema little-endian?Converte big endian in little endian durante la lettura da un file binario

Questo è un compito a casa, ma è solo un extra dato che i sistemi a scuola utilizzano il sistema big-endian. E 'solo che mi sono incuriosito e volevo farlo funzionare sul mio computer di casa anche

#include <iostream> 
#include <fstream> 

using namespace std; 

int main() 
{ 
    ifstream file; 

    file.open("file.bin", ios::in | ios::binary); 

    if(!file) 
     cerr << "Not able to read" << endl; 
    else 
    { 
     cout << "Opened" << endl; 

     int i_var; 
     double d_var; 

     while(!file.eof()) 
     { 
     file.read(reinterpret_cast<char*>(&i_var) , sizeof(int)); 
     file.read(reinterpret_cast<char*>(&d_var) , sizeof(double)); 
     cout << i_var << " " << d_var << endl; 
     } 
    } 
    return 0; 
} 

Risolto

So Big-endian VS Little-endian è solo un ordine inverso dei byte. Questa funzione che ho scritto sembra comunque servire al mio scopo. L'ho aggiunto qui nel caso in cui qualcun altro ne avesse bisogno in futuro. Questo è solo per il doppio, tuttavia, per l'intero utilizzare la funzione torak suggerita oppure è possibile modificare questo codice facendolo passare solo di 4 byte.

double swap(double d) 
{ 
    double a; 
    unsigned char *dst = (unsigned char *)&a; 
    unsigned char *src = (unsigned char *)&d; 

    dst[0] = src[7]; 
    dst[1] = src[6]; 
    dst[2] = src[5]; 
    dst[3] = src[4]; 
    dst[4] = src[3]; 
    dst[5] = src[2]; 
    dst[6] = src[1]; 
    dst[7] = src[0]; 

    return a; 
} 
+1

Anche se hai risolto il tuo problema di endianess, i formati in virgola mobile possono variare da una piattaforma all'altra. Non è possibile salvare i valori in virgola mobile su una piattaforma e aspettarsi di caricarli su un'altra piattaforma. E 'un requisito che fai questo binario? – sbi

+0

beh non è un requisito dato che l'assegnazione deve essere eseguita e visualizzata sui computer della scuola. È solo la mia curiosità che voglio sapere come leggere questo file binario su un computer Windows. – starcorn

+1

@sbi: quali piattaforme sono attualmente implementate in virgola mobile in non-IEE-754? – Kos

risposta

2

Supponendo che stiate andando avanti, è utile mantenere un piccolo file di libreria delle funzioni di supporto. 2 di queste funzioni dovrebbero essere swap endian per valori di 4 byte e valori di 2 byte. Per alcuni esempi solidi (incluso il codice) consulta this article.

Una volta che hai le tue funzioni di scambio, ogni volta che leggi un valore nell'endian sbagliato, chiama la funzione di scambio appropriata. A volte un punto di inciampo per le persone qui è che i valori di un singolo byte non devono essere scambiati con endian, quindi se stai leggendo qualcosa come un flusso di caratteri che rappresenta una stringa di lettere da un file, dovrebbe andare bene. È solo quando stai leggendo in un valore questo è più byte (come un valore intero) che devi scambiarli.

+0

in realtà mi confondo perché c'è un sacco di scambio diverso. In quell'articolo si trattava di scambi brevi, lunghi e fluttuanti. Qualcuno di questi swap funzionerà con i tipi di dati con cui lavoro? – starcorn

+0

Le soluzioni dipendono dalla dimensione del valore dei dati. Se hai un valore di 2 byte, usi 'ShortSwap()', se hai un valore di 4 byte 'LongSwap().' Il 'FloatSwap()' nell'esempio c'è un po 'di inutile, tranne che c'è un logico differenza tra lo storage float e lo storage lungo ... LongSwap funzionerà comunque correttamente su un float di 4 byte. Quello che hai fatto nella tua soluzione postata in cima è effettivamente la stessa cosa per un valore di 8 byte. – Bryan

+0

Il link ora è 404! –

4

Potreste essere interessati alla famiglia di funzioni ntohl. Questi sono progettati per trasformare i dati dalla rete all'ordine dei byte host. L'ordine dei byte di rete è big endian, quindi su sistemi big endian non fanno nulla, mentre lo stesso codice compilato su un sistema little endian eseguirà gli scambi di byte appropriati.

+0

c'è qualcosa di simile per il doppio? – starcorn

+1

Il modo in cui i numeri in virgola mobile sono rappresentati è più complicato (e varato) che per gli iter, e non l'ho mai provato quindi non sono sicuro al 100%. Tuttavia, supponendo che le rappresentazioni in virgola mobile sulle due macchine corrispondano (eccetto per endianness) l'articolo a cui Bryan si è collegato suggerisce che dovrebbe essere possibile. – torak

19

Si potrebbe utilizzare un modello per lo swap endian che sarà generalizzato per i tipi di dati:

#include <algorithm> 

template <class T> 
void endswap(T *objp) 
{ 
    unsigned char *memp = reinterpret_cast<unsigned char*>(objp); 
    std::reverse(memp, memp + sizeof(T)); 
} 

Poi il codice finirebbe per guardare qualcosa di simile:

file.read(reinterpret_cast<char*>(&i_var) , sizeof(int)); 
endswap(&i_var); 
file.read(reinterpret_cast<char*>(&d_var) , sizeof(double)); 
endswap(&d_var); 
cout << i_var << " " << d_var << endl; 
+0

Ho qualcosa di simile, ma prendendo l'oggetto per riferimento, anziché il puntatore. – sbi

4

Linux fornisce endian.h, che ha efficienti routine di scambio di endian fino a 64 bit. Inoltre tiene conto automaticamente della endianità del tuo sistema. Le funzioni a 32 bit sono definite in questo modo:

uint32_t htobe32(uint32_t host_32bits);   // host to big-endian encoding 
uint32_t htole32(uint32_t host_32bits);   // host to lil-endian encoding 
uint32_t be32toh(uint32_t big_endian_32bits);  // big-endian to host encoding 
uint32_t le32toh(uint32_t little_endian_32bits); // lil-endian to host encoding 

con funzioni con nomi simili per 16 e 64 bit. Quindi basta dire

x = le32toh(x); 

per convertire un intero a 32 bit nella codifica little-endian alla codifica CPU host. Questo è utile per leggere i dati little-endian.

x = htole32(x); 

convertirà dalla codifica host a little-endian a 32 bit. Questo è utile per scrivere dati little-endian.

Nota sui sistemi BSD, il file di intestazione equivalente è sys/endian.h

+1

Fate anche attenzione perché l'intestazione BSD è * non * assembly-safe, ovvero non potete includerla in alcun file assembly che fa parte del vostro programma C/C++. Questo mi ha fatto perché dopo aver letto l'intestazione di 'endian.h' di Linux, ho assunto implicitamente che tutte le intestazioni di' endian.h' fossero solo per il preprocessore, il che è sbagliato. Mettilo qui solo per evitare che qualcun altro cada nella stessa trappola. – Thomas

2

E 'bene aggiungere che la SM ha questo supportato su VS anche controllare questo funzioni inline:

  • htond
  • htonf
  • htonl
  • htonll
  • htons
Problemi correlati