C语言应用笔记:整数字节大小端翻转
在C语言中,实现大小端(Endian)翻转可以通过位操作或内存操作完成。以下提供两种常用方法:
方法1:位运算(推荐)
通过移位和掩码操作直接交换字节位置:
// 16位翻转(安全版本)
#define SWAP_ENDIAN_16(val) ({ \
uint16_t _val = (val); \
(((_val) >> 8) & 0x00FF) | \
(((_val) << 8) & 0xFF00); \
})
// 32位翻转(安全版本)
#define SWAP_ENDIAN_32(val) ({ \
uint32_t _val = (val); \
((_val & 0x000000FF) << 24) | \
((_val & 0x0000FF00) << 8) | \
((_val & 0x00FF0000) >> 8) | \
((_val & 0xFF000000) >> 24); \
})
// 64位翻转(安全版本)
#define SWAP_ENDIAN_64(val) ({ \
uint64_t _val = (val); \
((_val & 0x00000000000000FFULL) << 56) | \
((_val & 0x000000000000FF00ULL) << 40) | \
((_val & 0x0000000000FF0000ULL) << 24) | \
((_val & 0x00000000FF000000ULL) << 8) | \
((_val & 0x000000FF00000000ULL) >> 8) | \
((_val & 0x0000FF0000000000ULL) >> 24) | \
((_val & 0x00FF000000000000ULL) >> 40) | \
((_val & 0xFF00000000000000ULL) >> 56); \
})
方法2:内存操作
通过字节指针直接交换内存中的字节顺序:
// 16位大小端翻转
uint16_t swap_endian16(uint16_t value) {
uint8_t *bytes = (uint8_t *)&value;
return ((uint16_t)bytes[0] << 8) |
((uint16_t)bytes[1] << 0);
}
// 32位大小端翻转
uint32_t swap_endian32(uint32_t value) {
uint8_t *bytes = (uint8_t *)&value;
return ((uint32_t)bytes[0] << 24) |
((uint32_t)bytes[1] << 16) |
((uint32_t)bytes[2] << 8) |
((uint32_t)bytes[3] << 0);
}
// 64位大小端翻转
uint64_t swap_endian64(uint64_t value) {
uint8_t *bytes = (uint8_t *)&value;
return ((uint64_t)bytes[0] << 56) |
((uint64_t)bytes[1] << 48) |
((uint64_t)bytes[2] << 40) |
((uint64_t)bytes[3] << 32) |
((uint64_t)bytes[4] << 24) |
((uint64_t)bytes[5] << 16) |
((uint64_t)bytes[6] << 8) |
((uint64_t)bytes[7] << 0);
}
使用示例
#include "main.h"
int main(void) {
#ifdef ENDIAN_DEFINE
// 16位测试
uint16_t a = 0x1234;
printf("0x%04X -> 0x%04X\n", a, SWAP_ENDIAN_16(a));
// 32位测试
uint32_t b = 0x12345678;
printf("0x%08X -> 0x%08X\n", b, SWAP_ENDIAN_32(b));
// 64位测试
uint64_t c = 0x0123456789ABCDEF;
printf("0x%016llX -> 0x%016llX\n", c, SWAP_ENDIAN_64(c));
#else
// 16位测试
uint16_t a = 0x1234;
printf("0x%04X -> 0x%04X\n", a, swap_endian16(a));
// 32位测试
uint32_t b = 0x12345678;
printf("0x%08X -> 0x%08X\n", b, swap_endian32(b));
// 64位测试
uint64_t c = 0x0123456789ABCDEF;
printf("0x%016llX -> 0x%016llX\n", c, swap_endian64(c));
#endif
return 0;
}
输出结果
0x1234 -> 0x3412
0x12345678 -> 0x78563412
0x0123456789ABCDEF -> 0xEFCDAB8967452301
关键说明
- 原理:大小端翻转的本质是反转多字节数据在内存中的存储顺序(大端序高位在前,小端序低位在前)。
- 可移植性:上述代码不依赖主机字节序,可在任何平台使用。
- 效率:位运算通常比内存操作更快,编译器会优化为高效指令(如bswap)。
- 类型安全:使用stdint.h中的明确宽度类型(如uint32_t)避免平台差异。
注意:实际开发中可优先使用编译器内置函数(如GCC的__builtin_bswap32()),但上述手动实现更具通用性。