我最近在 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) 块中。这是一个common idiom,允许在宏之后使用正常的分号。
接下来是使用名为REVERSE_BYTES 的变量作为for 循环的计数器。宏本身的名称用作变量名称,以确保它不会与使用宏的范围内可能存在的任何其他符号冲突。由于该名称是在宏的扩展中使用的,所以在这里用作变量名时不会再次扩展。
在for 循环中,引用了两个字节和XOR swapped(因此不需要临时变量名):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__ 表示赋予宏的任何内容,用于增加可能传入的内容的灵活性(尽管幅度不大)。然后将该参数的地址转换为unsigned char 指针,以允许通过数组[] 下标交换其字节。
最后一个特殊点是缺少{} 大括号。它们不是必需的,因为每个交换中的所有步骤都与comma operator 结合在一起,使它们成为一个语句。
最后,值得注意的是,如果速度是重中之重,这并不是理想的方法。如果这是一个重要因素,则其他答案中引用的某些特定于类型的宏或特定于平台的指令可能是更好的选择。但是,这种方法可以移植到所有类型、所有主要平台以及 C 和 C++ 语言。