J'ai récemment écrit une macro pour le faire en C, mais elle est également valable 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)
Il accepte n'importe quel type et inverse les octets dans l'argument passé. Exemples d'utilisations:
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]);
}
Qui imprime:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Ce qui précède est parfaitement copiable / collable, mais il se passe beaucoup de choses ici, donc je vais vous expliquer comment cela fonctionne pièce par pièce:
La première chose notable est que la macro entière est enfermée dans un do while(0)
bloc. Ceci est un idiome commun permettant l'utilisation normale des points-virgules après la macro.
Ensuite, l'utilisation d'une variable nommée REVERSE_BYTES
comme for
compteur de boucle. Le nom de la macro lui-même est utilisé comme nom de variable pour garantir qu'il n'entre pas en conflit avec d'autres symboles qui peuvent être dans le champ d'application partout où la macro est utilisée. Étant donné que le nom est utilisé dans l'expansion de la macro, il ne sera pas développé à nouveau lorsqu'il est utilisé comme nom de variable ici.
Dans la for
boucle, deux octets sont référencés et XOR échangés (un nom de variable temporaire n'est donc pas requis):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
représente tout ce qui a été donné à la macro et est utilisé pour augmenter la flexibilité de ce qui peut être transmis (quoique pas beaucoup). L'adresse de cet argument est ensuite prise et transtypée en un unsigned char
pointeur pour permettre l'échange de ses octets via un []
indice de tableau .
Le dernier point particulier est le manque d' {}
appareils orthopédiques. Ils ne sont pas nécessaires car toutes les étapes de chaque échange sont jointes à l' opérateur virgule , ce qui en fait une instruction.
Enfin, il convient de noter que ce n'est pas l'approche idéale si la vitesse est une priorité absolue. S'il s'agit d'un facteur important, certaines des macros spécifiques au type ou des directives spécifiques à la plate-forme référencées dans d'autres réponses sont probablement une meilleure option. Cette approche, cependant, est portable pour tous les types, toutes les principales plates-formes et les langages C et C ++.