优先用二进制字面量(如0b1010'0001)声明协议字段常量,直观反映位定义;跨多字节字段用十六进制但须配合端序转换;八进制慎用;Python中字节与整数互转需显式指定长度和端序。

直接用字面量表达协议字段,比硬算十进制或靠注释猜含义更可靠。关键不是“会不会换算”,而是让代码本身就能反映协议设计意图。
用二进制字面量对齐位定义
协议里常规定“bit 7 是启动标志,bit 2-0 是操作码”,这时写 0b1000_0111 比 0x87 更直观——每一位的位置和作用一目了然。C++14、Rust、Java 7+、Python 3.6+ 都支持 0b 前缀;C 需 C99 起,嵌入式若受限可改用十六进制等价写法(如 0b11001001 → 0xC9),但建议加注释说明原始位意图。
- 推荐搭配单引号分隔符:如 0b1010'0001'1100'0011,按字节或功能段分组,提升可读性
- 避免在宏或常量中拼接位运算表达式(如 (1<<7) | (3&0x07)),编译期虽等价,但调试时难追溯原始协议定义
- 寄存器配置、SPI/I2C 命令字、CAN 报文控制字段等场景优先使用二进制字面量声明具名常量
十六进制用于紧凑表示多字节字段
当协议字段跨多个字节(如 4 字节命令 ID、6 字节 MAC 地址),十六进制更简洁。但注意:0x12345678 这个值本身无字节序,它只是整数;真正出问题的是你把它写入内存或 buffer 的方式。
- 协议文档写的 0x12345678 通常按大端描述,小端机器上若直接赋值给 uint32_t 后 memcpy,抓包会看到 78 56 34 12
- 正确做法:用宏定义协议值(如 #define CMD_RESET 0x00000001UL),再配合 htonl(CMD_RESET) 写入网络 buffer
- 结构体中字段不建议直接按协议顺序排列,应显式用 memcpy(&buf[off], &val, sizeof(val)) 并确保 val 已转为目标端序
八进制字面量慎用,仅限特定场景
八进制(以 0 开头,如 0755)在 Python 和旧版 C 中存在,但现代协议开发中极少直接使用。它主要价值在于 Linux 权限、某些硬件寄存器的低三位分组解释等固定模式场景。
- Python 中八进制必须写成 0o755(带 o),旧写法 0755 在 Python 3.0+ 已废弃
- C/C++ 中以 0 开头即为八进制,容易误写(如 088 编译报错),不推荐用于协议常量
- 若协议明确要求按三位一组解释字段(如状态寄存器低 3 位为 mode),可用 0b000_111 或注释说明“等价于八进制 0o7”,不依赖八进制字面量本身
Python 中字节与整数互转要严控长度和端序
Python 的 int.to_bytes() 和 int.from_bytes() 很方便,但默认大端,且 length 参数必须精确匹配协议字段宽度。
- 写错长度会导致高位补零(污染后续字段)或抛 OverflowError(如用 2 字节表示 0x10000)
- 构造协议包时,显式指定 length=2, byteorder='big' 或 'little',不要依赖默认
- 从网络收包解析时,先按协议字段长度切片(如 data[4:6]),再用 int.from_bytes(..., 'big') 解析,避免因整数自动扩展引入歧义

















