Saya baru-baru ini menulis makro untuk melakukan ini dalam C, tetapi sama-sama valid di 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)
Ia menerima segala jenis dan membalik byte dalam argumen yang diteruskan. Contoh penggunaan:
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]);
}
Yang mencetak:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Di atas sempurna copy / paste-mampu, tetapi ada banyak hal yang terjadi di sini, jadi saya akan memecah cara kerjanya sepotong demi sepotong:
Hal penting pertama adalah bahwa seluruh makro terbungkus dalam sebuah do while(0)
blok. Ini adalah ungkapan yang umum untuk memungkinkan penggunaan titik koma normal setelah makro.
Selanjutnya adalah penggunaan variabel bernama REVERSE_BYTES
sebagai for
penghitung loop. Nama makro itu sendiri digunakan sebagai nama variabel untuk memastikan bahwa itu tidak berbenturan dengan simbol lain yang mungkin ada di ruang lingkup di mana makro digunakan. Karena nama sedang digunakan dalam ekspansi makro, itu tidak akan diperluas lagi ketika digunakan sebagai nama variabel di sini.
Dalam for
loop, ada dua byte yang direferensikan dan XOR ditukar (jadi nama variabel sementara tidak diperlukan):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
mewakili apa pun yang diberikan kepada makro, dan digunakan untuk meningkatkan fleksibilitas dari apa yang mungkin diteruskan (meskipun tidak banyak). Alamat argumen ini kemudian diambil dan dilemparkan keunsigned char
pointer untuk memungkinkan pertukaran byte-nya melalui []
subscript array .
Poin aneh terakhir adalah kurangnya {}
kawat gigi. Mereka tidak perlu karena semua langkah dalam setiap swap bergabung dengan operator koma , menjadikannya satu pernyataan.
Akhirnya, perlu dicatat bahwa ini bukan pendekatan yang ideal jika kecepatan adalah prioritas utama. Jika ini merupakan faktor penting, beberapa makro spesifik-jenis atau arahan khusus platform yang dirujuk dalam jawaban lain kemungkinan merupakan pilihan yang lebih baik. Pendekatan ini, bagaimanapun, adalah portabel untuk semua jenis, semua platform utama, dan kedua bahasa C dan C ++.