C语言应用笔记:整数字节大小端翻转

yumo6662小时前技术文章1

在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

关键说明

  1. 原理:大小端翻转的本质是反转多字节数据在内存中的存储顺序(大端序高位在前,小端序低位在前)。
  2. 可移植性:上述代码不依赖主机字节序,可在任何平台使用。
  3. 效率:位运算通常比内存操作更快,编译器会优化为高效指令(如bswap)。
  4. 类型安全:使用stdint.h中的明确宽度类型(如uint32_t)避免平台差异。

注意:实际开发中可优先使用编译器内置函数(如GCC的__builtin_bswap32()),但上述手动实现更具通用性。

相关文章

数据结构-位运算_数据结构按位查找

左移( << ):操作数的非0位左移n位,低位补0右移( >> ):操作数的非0位右移n位,高位补0无符号右移( >>> ):正数右移,高位用0补,负数右移,...

PLC的位逻辑运算指令_plc中的位怎么理解

PLC(可编程逻辑控制器)的位指令是针对单个二进制位(0 或 1)进行操作的基础指令,主要用于逻辑控制,是梯形图(LD)编程中最常用的指令类型。以下是 PLC 位指令的核心类别及常用指令:常开常闭输出...

【C语言·015】逗号运算符的求值顺序与返回值规则

很多人第一次看到 , 都把它当“分隔符”:函数实参之间的逗号、初始化列表里的逗号……但在表达式里,, 还有另一个身份——逗号运算符。它既能强制求值顺序,又能控制返回值,是解决副作用与顺序问题的一把小刀...

C 语言指针全解析:从门牌号到内存黑魔法,一文带你彻底搞懂!

很多人一提到 C 语言指针 就皱眉:“指针是不是地址?”“数组和指针是不是一样的?”“为什么 * 有时候是解引用,有时候是乘法?”其实指针没那么神秘。只要把它拆开理解,就会发现它不过是一串数字,存的就...

C语言应用笔记:获取结构体成员偏移地址

在C语言中,获取结构体成员的偏移地址(即成员相对于结构体起始地址的字节偏移量)有两种常用方法:1. 使用标准库宏 offsetof(推荐)<stddef.h> 头文件提供了 offseto...