最近、C でこれを行うマクロを作成しましたが、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)
任意の型を受け入れ、渡された引数のバイトを逆にします。使用例:
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]);
}
どちらが印刷されますか:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
上記は完全にコピー/貼り付け可能ですが、ここでは多くのことが行われているため、どのように機能するかを少しずつ説明します。
最初に注目すべきことは、マクロ全体がdo while(0)ブロックに含まれていることです。これは、マクロの後に通常のセミコロンの使用を許可する一般的なイディオムです。
次は、ループのカウンターREVERSE_BYTESとして名前が付けられた変数の使用です。forマクロ自体の名前は変数名として使用され、マクロが使用される場所でスコープ内にある他のシンボルと衝突しないようにします。この名前はマクロの展開内で使用されているため、ここで変数名として使用すると再度展開されません。
forループ内では、 2 バイトが参照され、 XOR スワップされます(したがって、一時変数名は必要ありません)。
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__マクロに与えられたものを表し、渡される可能性のあるものの柔軟性を高めるために使用されます (それほどではありませんが)。次に、この引数のアドレスが取得されてunsigned charポインターにキャストされ、配列の[]添字によるバイトの交換が可能になります。
最後の特異な点は、{}ブレースがないことです。各スワップのすべてのステップがコンマ operatorで結合され、 1 つのステートメントになるため、それらは必要ありません。
最後に、速度が最優先事項である場合、これは理想的なアプローチではないことに注意してください。これが重要な要素である場合、他の回答で参照されているタイプ固有のマクロまたはプラットフォーム固有のディレクティブのいくつかがより適切なオプションである可能性があります。ただし、このアプローチは、すべての型、すべての主要なプラットフォーム、および C 言語と C++ 言語の両方に移植できます。