C 语言字节序与位操作
更新时间:2026-08-26。本文是
languages/c/主题专家层文档。写网络协议、解析二进制格式、做序列化时,有两个基本功绕不开:字节序(多字节整数在内存里怎么排)和位操作(用位表示标志、掩码)。本文用实测讲透,避免"跨平台传输数据乱了"的经典翻车。
本文要回答的问题
- 什么是大端、小端?你的机器是哪一种?
- 网络传输数据为什么要转换字节序?
ntohl是干什么的? - 位操作怎么置位、清位、取位?位域结构体好用吗?
一、字节序:多字节整数怎么排
一个 uint32_t(4 字节)在内存里的排列顺序,有两种:
text
数值 0x12345678 的内存表示:
大端(big-endian): 12 34 56 78 ← 高字节在低地址
小端(little-endian):78 56 34 12 ← 低字节在低地址实测(x86-64):
c
uint32_t x = 0x12345678;
unsigned char *p = (unsigned char *)&x;
printf("%02x %02x %02x %02x\n", p[0], p[1], p[2], p[3]);text
本机字节序: 78 56 34 12 => 小端(little-endian)x86/ARM(主流)都是小端,网络协议规定大端——这就是跨平台传输数据必须转换的原因。
二、网络字节序转换
网络传输统一用大端(网络字节序),所以发送前要转换:
c
#include <arpa/inet.h>
uint32_t host = 0x12345678;
uint32_t net = htonl(host); // Host TO Network Long:转大端
uint32_t back = ntohl(net); // Network TO Host:转回本机
uint16_t port = htons(8080); // 短整型转换| 函数 | 含义 |
|---|---|
htonl / ntohl | 32 位(long):本机 ↔ 网络 |
htons / ntohs | 16 位(short):本机 ↔ 网络 |
要点:无论本机是大端还是小端,htonl/ntohl 都保证正确转换(本机是大端时它们是空操作)。
现代做法也可用
__builtin_bswap32(字节交换),或 C 的位运算手动转——但网络编程用htonl族最标准。
三、位操作
用单个整数存多个布尔标志,是位操作的经典用途:
c
uint32_t flags = 0;
// 置位(set)
flags |= (1u << 3); // 第 3 位置 1
flags |= (1u << 7); // 第 7 位置 1
// 检测(test)
if (flags & (1u << 3)) { ... } // 第 3 位是否为 1
int bit7 = (flags >> 7) & 1; // 取第 7 位
// 清位(clear)
flags &= ~(1u << 3); // 第 3 位清 0
// 翻转(toggle)
flags ^= (1u << 3); // 第 3 位取反实测:
text
flags = 0x00000088, 第3位=1, 第7位=1位操作速查
| 操作 | 表达式 |
|---|---|
| 置位 | x |= (1 << n) |
| 清位 | x &= ~(1 << n) |
| 翻转 | x ^= (1 << n) |
| 检测 | (x >> n) & 1 |
| 掩码 | x & MASK |
四、位域结构体
C 的位域能按"位"定义结构体字段:
c
struct Flags {
unsigned int a : 1; // 1 位
unsigned int b : 3; // 3 位
unsigned int c : 4; // 4 位
};
// 总共 8 位 = 1 字节(但可能对齐到 4 字节)位域省内存,但有坑:
| 坑 | 说明 |
|---|---|
| 布局不可移植 | 位域的排列顺序、是否跨字节,标准不规定 |
| 对齐导致体积膨胀 | 位域整体可能对齐到 int(4 字节) |
| 不能取地址 | 位域成员不能用 & 取地址 |
建议:跨平台协议解析、网络传输场景,别用位域(布局不确定),用手动位操作 + 掩码更可靠。
五、序列化的坑
跨平台传输结构体时,直接 send 整个结构体是危险的:
c
// 危险:字节序、对齐、padding 都可能导致数据错乱
struct Packet { int type; char data[10]; };
send(fd, &packet, sizeof(packet), 0); // 对端可能解析错正确做法:逐字段转换字节序(htonl/htons),或用标准序列化格式(JSON、protobuf)。
六、与本站主线衔接
- 网络 IO:字节序在网络编程中的应用,见 网络编程。
- 结构体布局:padding 与字节序的关系,见 结构体布局与对齐深入。
- 内存表示:多字节整数的内存表示,见 数据类型与内存表示。
- 协议解析:二进制协议与字节序,见 网络协议。
一句话总结
字节序是多字节整数的内存排列(x86 是小端、网络是大端),跨平台传输要用 htonl/ntohl 转换;位操作用 1<<n 的置位/清位/检测管理标志,位域省内存但不可移植;协议解析别直接发结构体,逐字段转换才可靠。