Recientemente escribí una macro para hacer esto en C, pero es igualmente válido en 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)
Acepta cualquier tipo e invierte los bytes en el argumento pasado. Usos de ejemplo:
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]);
}
Que imprime:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Lo anterior es perfectamente compatible con copiar / pegar, pero están sucediendo muchas cosas aquí, así que desglosaré cómo funciona pieza por pieza:
Lo primero notable es que toda la macro está encerrada en un do while(0)
bloque. Este es un idioma común para permitir el uso normal de punto y coma después de la macro.
El siguiente es el uso de una variable llamada REVERSE_BYTES
como for
contador del bucle. El nombre de la macro en sí se usa como un nombre de variable para garantizar que no entre en conflicto con ningún otro símbolo que pueda estar en el lugar donde se usa la macro. Dado que el nombre se está utilizando dentro de la expansión de la macro, no se expandirá nuevamente cuando se use como nombre de variable aquí.
Dentro del for
bucle, se hace referencia a dos bytes y se intercambia XOR (por lo que no se requiere un nombre de variable temporal):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
representa lo que se le dio a la macro y se usa para aumentar la flexibilidad de lo que se puede pasar (aunque no mucho). La dirección de este argumento se toma y se envía a ununsigned char
puntero para permitir el intercambio de sus bytes a través de la []
suscripción de la matriz .
El último punto peculiar es la falta de {}
frenillos. No son necesarios porque todos los pasos de cada intercambio se unen con el operador de coma , lo que los convierte en una declaración.
Finalmente, vale la pena señalar que este no es el enfoque ideal si la velocidad es una prioridad. Si este es un factor importante, algunas de las macros específicas de tipo o directivas específicas de plataforma a las que se hace referencia en otras respuestas son probablemente una mejor opción. Sin embargo, este enfoque es portátil para todos los tipos, todas las plataformas principales y los lenguajes C y C ++.