/ / Qual è il modo più veloce per cambiare endianness durante la lettura da un file con C ++? - c ++, prestazioni, file, endianness

Qual è il modo più veloce per cambiare endianness durante la lettura da un file con C ++? - c ++, prestazioni, file, endianness

Mi è stato fornito un file binario da leggere, checontiene una sequenza di valori grezzi. Per semplicità supponiamo di avere valori interi non firmati, a 4 o 8 byte. Sfortunatamente per me, l'ordine dei byte per questi valori è incompatibile con l'endianità del mio processore (poco contro grande o viceversa; non importa niente di strano PDF-endianness, ecc.); e voglio questi dati in memoria con il corretto endianness.

Qual è il modo più veloce per farlo, considerando il fatto che sto leggendo i dati da un file? Se non vale la pena sfruttare questo fatto, ti preghiamo di spiegarne il motivo.

risposte:

2 per risposta № 1

Considerando il fatto che stai leggendo i dati da un file, il modo in cui cambi endianness avrà un effetto insignificante sul runtime, rispetto a ciò che fa il file-IO.

Ciò che potrebbe fare una differenza significativa è comeleggi i dati. Cercare di leggere i byte fuori ordine non sarebbe una buona idea. Basta leggere i byte in ordine e in seguito cambiare endianness. Questo separa la lettura e lo scambio di byte.

Che cosa io volere dal byte scambiare il codice in genere, e certamente nel caso di leggere un file, è che funzioni per qualsiasi endianness e non dipende da istruzioni specifiche di architechture.

char* buf = read(); // let buf be a pointer to the read buffer
uint32_t v;

// little to native
v = 0;
for(unsigned i = 0; i < sizeof v; i++)
v |= buf[i] << CHAR_BIT * i;

// big to native
v = 0;
for(unsigned i = 0; i < sizeof v; i++)
v |= buf[i] << CHAR_BIT * (sizeof v - i);

Questo funziona se il nativo è grande, piccolo o una delle varietà middle endian.

Ovviamente, Incremento li ha già implementati per te, quindi non c'è bisogno di re-implementarli. Inoltre, ci sono i ntoh? famiglia di funzioni fornite sia da POSIX che dalla libreria Windows C, che può essere utilizzata per convertire big endian da / a nativo.


1 per risposta № 2

Non il più veloce, ma un modo portabile sarebbe quello di leggere il file in un array int (senza segno), alias l'array int in uno char (consentito per la regola di aliasing rigida) e scambiare byte in memoria.

Modo completamente portatile:

swapints(unsigned int *arr, size_t l) {
unsigned int cur;
char *ix;
for (size_t i=0; i<l; i++) {
int cur;
char *dest = static_cast<char *>(&cur) + sizeof(int);
char *src = static_cast<char *>(&(arr[i]));
for(int j=0; j<sizeof(int); j++) *(--dest) = *(src++);
arr[i] = cur;
}
}

Ma se non hai bisogno di portabilità, alcuni sistemi offrono funzioni di scambio. Ad esempio, i sistemi BSD hanno bswap16, bswap32 e bswap64 scambiare byte in uint16_t, uint32_t e uint_64_t rispettivamente. Senza dubbio esistono funzioni equivalenti nei mondi Microsoft o GNU-Linux.

In alternativa, se sai che il file è in Rete ordine (big endian) e il tuo processore no, puoi usare il ntohs e ntohl funzioni per rispettivamente uint16_t e uint32_t.

Nota (secondo il commento di AndrewHenle): qualunque sia l'endianità dell'ospite, ntohs e ntohl può sempre essere usato - semplicemente sono no-op sui sistemi big-endian