2011-09-08 18 views
8

Ho bisogno di scambiare in modo efficiente l'ordine dei byte di un array durante la copia in un altro array.Byte swap durante la copia

L'array di origine è di un certo tipo; char, short o int così lo scambio di byte richiesto non è ambiguo e sarà secondo quel tipo.

Il mio piano è quello di fare questo molto semplicemente con una copia byte-saggio multi-pass (2 in breve, 4 per int, ...). Esistono comunque delle funzioni o librerie "memcpy_swap_16/32/64" preesistenti? Forse nell'elaborazione delle immagini per l'elaborazione di immagini BGR/RGB.

EDIT

so come scambiare i byte di valori individuali, che non è il problema. Voglio fare questo processo durante una copia che eseguirò comunque.

Ad esempio, se si dispone di un array o di piccoli numeri interi endian a 4 byte, è possibile effettuare uno scambio eseguendo copie a 4 byte con offset iniziale di 0, 1, 2 e 3 con un passo di 4. Tuttavia, potrebbero esserci un modo migliore, forse anche leggendo ogni intero di 4 byte individualmente e utilizzando gli intrinsecamente byte-swap _byteswap_ushort, _byteswap_ulong e _byteswap_uint64 sarebbe più veloce. Ma sospetto che ci siano funzioni esistenti che eseguono questo tipo di elaborazione.

EDIT 2

appena trovato questo, che può essere una base utile per SSE, anche se è vero che la larghezza di banda della memoria, probabilmente lo rende una perdita di tempo.

Fast vectorized conversion from RGB to BGRA

risposta

1

Sì, ci sono funzioni esistenti come quella collegata nella domanda, ma non ne vale la pena perché la dimensione dei dati (in questo caso) indica che l'overhead impostato è troppo alto. Quindi, invece, è meglio leggere solo 2, 4 e 8 byte alla volta e fare lo scambio usando intrinseci e riscrivi.

6

sistemi Unix hanno una funzione swab che fa quello che si vuole per gli array a 16 bit. Probabilmente è ottimizzato, ma non ne sono sicuro. Si noti che gcc moderna genererà il codice estremamente efficiente se basta scrivere il codice di byte di swap ingenua:

uint32_t x, y; 
y = (x<<24) | (x<<8 & 0xff0000) | (x>>8 & 0xff00) | (x>>24); 

vale a dire che verrà utilizzare l'istruzione bswap su i486 +. Presumibilmente mettere questo in un ciclo darà un ciclo efficiente troppo ...

Edit: Per il vostro compito di copia, lo farei quanto segue nel ciclo:

  1. leggere un valore a 32 bit da const uint32_t *src.
  2. Utilizzare il codice sopra riportato per scambiarlo.
  3. Scrivere un valore a 32 bit su uint32_t *dest.

rigor di termini questo potrebbe non essere portatili (violazioni aliasing), ma fino a quando la funzione di copia è in una propria unità di traduzione e non ottenere inline, c'è ben poco di cui preoccuparsi. Dimentica ciò che ho scritto sull'aliasing; se si stanno scambiando i dati come valori a 32 bit, in realtà erano quasi sicuramente valori a 32 bit, non un altro tipo di puntatore che è stato lanciato, quindi non c'è alcun problema.

+1

I byte del compiler swap intrinsics sono un modo migliore per garantire l'uso dell'istruzione corretta. Ma questo non è il problema. – hplbsh

+0

Non so perché li chiameresti "migliori". Sono specifici per un particolare compilatore. Il codice che ho dato genererà l'istruzione "corretta" su qualsiasi compilatore che in realtà si preoccupa di ottimizzare. –

+0

Perché sarà veloce anche nelle build di debug non ottimizzate. – hplbsh

3

In Linux, è necessario controllare l'intestazione bits/byteswap.h. c'è una famiglia di macro del modulo bswap _ ##, e alcuni di essi usano le istruzioni di assemblaggio dove appropriato.

+2

Questa intestazione, come scritto, è un abominio: usano l'assembly inline per renderlo "veloce", quindi le estensioni gcc per favorire C sull'assembly quando gli argomenti sono costanti in modo che gcc possa comprimere le costanti. ed ecco cosa lo rende quasi divertente se non fosse così triste - gcc genererà lo stesso o meglio asm da solo se si scrive solo l'ingenuo C come ho scritto nella mia risposta. –

+0

@R. contiene 16,32 , Implementazioni a 64 bit e gestisce correttamente i sistemi a 32/64 bit e lo rende semplice come 'bswap_16 (...)'. –

+0

Concordo sul fatto che le funzioni siano utili.Pongo solo che l'intestazione sia scritta in modo orribile. e le estensioni gcc ne sono state estratte, il codice generato sarebbe altrettanto buono o meglio, e la possibilità di bug e incompatibilità sarebbe quasi eliminata. Inoltre, pulirlo sarebbe di aiuto nell'insegnare i principianti a non praticare l'ottimizzazione prematura ... –