Recentemente, escrevi uma macro para fazer isso em C, mas é igualmente válida em 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)
Ele aceita qualquer tipo e reverte os bytes no argumento passado. Exemplos de usos:
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
O acima é perfeitamente capaz de copiar / colar, mas há muita coisa acontecendo aqui, então vou detalhar como funciona peça por peça:
A primeira coisa notável é que toda a macro está encerrada em um do while(0)
bloco. Este é um idioma comum para permitir o uso normal de ponto e vírgula após a macro.
A seguir, o uso de uma variável nomeada REVERSE_BYTES
como for
contador do loop. O nome da macro em si é usado como um nome de variável para garantir que não colidir com outros símbolos que possam estar no escopo onde quer que a macro seja usada. Como o nome está sendo usado na expansão da macro, ele não será expandido novamente quando usado como um nome de variável aqui.
Dentro do for
loop, há dois bytes sendo referenciados e trocados por XOR (portanto, um nome temporário de variável não é necessário):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
representa o que foi dado à macro e é usado para aumentar a flexibilidade do que pode ser passado (embora não muito). O endereço desse argumento é levado e convertido em um unsigned char
ponteiro para permitir a troca de seus bytes via array[]
assinatura de .
O ponto peculiar final é a falta de {}
aparelho. Eles não são necessários porque todas as etapas de cada troca são unidas ao operador de vírgula , tornando-as uma declaração.
Por fim, vale ressaltar que essa não é a abordagem ideal se a velocidade for uma prioridade. Se esse é um fator importante, algumas das macros específicas de tipo ou diretivas específicas de plataforma mencionadas em outras respostas provavelmente são uma opção melhor. Essa abordagem, no entanto, é portátil para todos os tipos, todas as principais plataformas e as linguagens C e C ++.