Gần đây tôi đã viết một macro để làm điều này trong C, nhưng nó có giá trị như nhau trong 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)
Nó chấp nhận bất kỳ loại nào và đảo ngược các byte trong đối số được truyền. Ví dụ sử dụng:
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]);
}
Bản in nào:
Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman
Ở trên hoàn toàn có thể sao chép / dán, nhưng có rất nhiều thứ đang diễn ra ở đây, vì vậy tôi sẽ chia nhỏ cách thức hoạt động của từng mảnh:
Điều đáng chú ý đầu tiên là toàn bộ macro được bọc trong một do while(0)
khối. Đây là một thành ngữ phổ biến để cho phép sử dụng dấu chấm phẩy bình thường sau macro.
Tiếp theo là việc sử dụng một biến có tên REVERSE_BYTES
làfor
đếm của vòng lặp. Tên của macro được sử dụng làm tên biến để đảm bảo rằng nó không xung đột với bất kỳ ký hiệu nào khác có thể nằm trong phạm vi bất cứ nơi nào macro được sử dụng. Vì tên đang được sử dụng trong phần mở rộng của macro, nên nó sẽ không được mở rộng lại khi được sử dụng làm tên biến ở đây.
Trong for
vòng lặp, có hai byte được tham chiếu và XOR hoán đổi (vì vậy không cần phải có tên biến tạm thời):
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]
__VA_ARGS__
đại diện cho bất cứ điều gì đã được trao cho macro và được sử dụng để tăng tính linh hoạt của những gì có thể được truyền vào (mặc dù không nhiều). Địa chỉ của đối số này sau đó được lấy và chuyển sang một unsigned char
con trỏ để cho phép hoán đổi các byte của nó thông qua mảng[]
đăng ký .
Điểm đặc biệt cuối cùng là thiếu {}
niềng răng. Chúng không cần thiết vì tất cả các bước trong mỗi trao đổi được nối với toán tử dấu phẩy , biến chúng thành một câu lệnh.
Cuối cùng, điều đáng chú ý là đây không phải là phương pháp lý tưởng nếu tốc độ là ưu tiên hàng đầu. Nếu đây là một yếu tố quan trọng, một số macro cụ thể theo loại hoặc chỉ thị dành riêng cho nền tảng được tham chiếu trong các câu trả lời khác có thể là một lựa chọn tốt hơn. Tuy nhiên, cách tiếp cận này có thể di động cho tất cả các loại, tất cả các nền tảng chính và cả ngôn ngữ C và C ++.