嵌入式 C:端序转换
更新时间:2026-09-21。嵌入式/裸机视角。字节序基础见 字节序(大端/小端)。
一句话回答
端序转换就是把多字节数据在「主机字节序」和「网络字节序(大端)」之间互转:用 htonl/htons(host→network)发送、ntohl/ntohs(network→host)接收;在裸机没有这些库函数时,用移位把字节逐个拼装,或用编译器内建 __builtin_bswap32 做字节交换。
一、标准库函数
c
#include <arpa/inet.h> /* Linux/有网络栈时 */
uint32_t v = 0x12345678;
uint32_t n = htonl(v); /* 主机序 -> 网络序(大端),用于发送 */
uint32_t h = ntohl(n); /* 网络序 -> 主机序,用于接收 */h= host,n= network;s= 16 位 short,l= 32 位 long;- 它们是「转成/转自网络序」:在大端机器上可能是空操作,在小端机器上才真正交换字节,所以无脑成对调用即可,可移植。
二、裸机手写字节交换
很多裸机环境没有 <arpa/inet.h>,用移位即可:
c
#include <stdint.h>
static inline uint16_t bswap16(uint16_t x) {
return (uint16_t)(((x & 0xFF00u) >> 8) |
((x & 0x00FFu) << 8));
}
static inline uint32_t bswap32(uint32_t x) {
return ((x & 0xFF000000u) >> 24) |
((x & 0x00FF0000u) >> 8) |
((x & 0x0000FF00u) << 8) |
((x & 0x000000FFu) << 24);
}编译器也提供内建:__builtin_bswap16/__builtin_bswap32/__builtin_bswap64(GCC/Clang),常被编译成单条 rev/bswap 指令。
三、更稳的做法:按字节拼装解析
从缓冲区解析大端字段时,不依赖主机字节序,直接按偏移取字节拼:
c
/* 从 buf 解析一个大端 uint32(任意主机端序都正确) */
uint32_t be32 = ((uint32_t)buf[0] << 24) |
((uint32_t)buf[1] << 16) |
((uint32_t)buf[2] << 8) |
((uint32_t)buf[3]);常见坑
- 该转不转:小端 MCU 直接把
uint32按大端协议发出去,高低字节颠倒。 - 重复转换:
htonl(htonl(x))又换回原值;转换后的数据当主机数继续做算术会错。 - 用强转/指针直接取:
*(uint16_t*)buf既依赖端序又可能因未对齐触发硬 fault。 - 混用 16/32 位函数:对 32 位字段用了
htons,只交换一半。
总结
发送多字节网络/大端字段用 htons/htonl、接收用 ntohs/ntohs,成对使用可移植;裸机用移位或 __builtin_bswap 手写交换,最稳的是按字节偏移显式拼装,避免直接指针强转引入端序和对齐风险。