Di recente ho scritto una macro per farlo in C, ma è ugualmente valido in C ++:
#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)
Accetta qualsiasi tipo e inverte i byte nell'argomento passato. Esempi di utilizzo:
int main(){
unsigned long long x = 0xABCDEF0123456789;
printf("Before: %llX\n",x);
REVERSE_BYTES(x);
printf("After : %llX\n",x);
char c[7]="nametag";
printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
REVERSE_BYTES(c);
printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}
Che stampa:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Quanto sopra è perfettamente copiabile / incollabile, ma c'è molto da fare qui, quindi analizzerò come funziona pezzo per pezzo:
La prima cosa degna di nota è che l'intera macro è racchiusa in un do while(0)
blocco. Questo è un linguaggio comune per consentire il normale uso del punto e virgola dopo la macro.
Il prossimo è l'uso di una variabile chiamata REVERSE_BYTES
come for
contatore del loop. Il nome della macro stessa viene utilizzato come nome di una variabile per garantire che non sia in conflitto con altri simboli che potrebbero trovarsi nell'ambito nell'ambito della macro. Poiché il nome viene utilizzato all'interno dell'espansione della macro, non verrà più espanso se utilizzato come nome di variabile qui.
All'interno del for
ciclo, ci sono due byte a cui viene fatto riferimento e scambiati XOR (quindi non è richiesto un nome di variabile temporaneo):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
rappresenta tutto ciò che è stato dato alla macro e viene utilizzato per aumentare la flessibilità di ciò che può essere passato (anche se non di molto). L'indirizzo di questo argomento viene quindi preso e trasmesso a un unsigned char
puntatore per consentire lo scambio dei suoi byte tramite array[]
sottoscrizione di .
L'ultimo punto peculiare è la mancanza di {}
parentesi graffe. Non sono necessari perché tutti i passaggi di ogni scambio sono uniti con l' operatore virgola , rendendoli un'istruzione.
Infine, vale la pena notare che questo non è l'approccio ideale se la velocità è una priorità assoluta. Se questo è un fattore importante, alcune delle macro specifiche del tipo o delle direttive specifiche della piattaforma citate in altre risposte sono probabilmente un'opzione migliore. Questo approccio, tuttavia, è portatile per tutti i tipi, tutte le principali piattaforme e entrambi i linguaggi C e C ++.