/* ==================== 小端 int16 解析 ==================== */
static inline int16_t _i16le(const uint8_t *b)
{
    return (int16_t)((uint16_t)b[1] << 8 | b[0]);
}

小端 int16 解析函数详解

我来给你逐行、逐位讲清楚这段代码的作用、原理和细节,你一看就懂。

代码功能总结

这是一个内联函数,作用是:
从一段小端格式的字节数组中,解析出一个 16 位有符号整数(int16_t)


逐行拆解

/* ==================== 小端 int16 解析 ==================== */
// static inline:静态内联函数,编译时直接展开,无函数调用开销
static inline int16_t _i16le(const uint8_t *b)
{
    // 核心:小端字节组合 → 16位有符号整数
    return (int16_t)((uint16_t)b[1] << 8 | b[0]);
}

1. 函数参数

  • const uint8_t *b:指向连续2个字节的指针(uint8_t = 无符号8位/1字节)
  • 要求:b 必须有效,且至少有 2 个字节可读

2. 核心表达式解析

(uint16_t)b[1] << 8 | b[0]

我们一步一步算:

  1. b[0]:低字节(小端存储的第一个字节)
  2. b[1]:高字节(小端存储的第二个字节)
  3. b[1] << 8
    把高字节左移 8 位,放到 16 位数的高 8 位
  4. | b[0]
    按位或,把低字节放到 16 位数的低 8 位
  5. (uint16_t) 强转
    防止移位时溢出/符号干扰,先按无符号拼接

小端存储是什么?(关键)

  • 小端(Little-Endian)低字节存低地址,高字节存高地址
  • int16 由 2 字节组成:高8位 + 低8位
  • 内存里的顺序是:
    地址:  [0]     [1]
    内容:  低字节   高字节
    

所以解析时必须:
高字节 << 8 | 低字节


举个例子(最直观)

假设内存字节是:

uint8_t bytes[] = {0x34, 0x12}; // 小端存储

执行:

_i16le(bytes);

计算过程:

  1. b[0] = 0x34(低字节)
  2. b[1] = 0x12(高字节)
  3. 0x12 << 8 = 0x1200
  4. 0x1200 | 0x34 = 0x1234
  5. 强转 int16_t → 结果 = 0x1234(十进制 4660)

为什么要这么写?

  1. 网络/串口/文件常用小端存储
  2. 跨平台解析二进制数据必须手动拼字节
  3. static inline 让函数零开销,性能极高
  4. 先转 uint16_t 再拼,避免符号位干扰

安全注意事项

  • 传入的指针 b 必须至少有 2 个有效字节
  • 不能传 NULL
  • 适用于所有支持 C99 及以上的编译器(ARM、x86、单片机都能用)

总结

  1. 功能:小端 2 字节 → int16 有符号整数
  2. 公式(高字节 << 8) | 低字节
  3. 优点:高效、通用、无平台依赖
  4. 用途:解析协议、文件、串口数据
posted on 2026-04-14 10:17  快乐的乙炔  阅读(21)  评论(0)    收藏  举报