私は最近これを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
ポインターにキャストされて、配列の[]
添え字によるバイトのスワッピングが可能になります。
最後の特異点は、{}
ブレースがないことです。各スワップのすべてのステップがカンマ演算子で結合され、1つのステートメントになるため、これらは必要ありません。
最後に、速度が最優先事項である場合、これは理想的なアプローチではないことに注意してください。これが重要な要素である場合、他の回答で参照されているタイプ固有のマクロまたはプラットフォーム固有のディレクティブのいくつかが、より良いオプションである可能性があります。ただし、このアプローチは、すべてのタイプ、すべての主要なプラットフォーム、およびC言語とC ++言語の両方に移植可能です。