两种有符号十转十六进制方法–偏移法和补码法

33 次阅读

本文最后更新于 2026年8月22日。

先把核心结论放前面:

T = val + 128偏移映射法(单极性偏移)
val + 256二进制补码标准算法(Two’s complement)
两者数学含义、取值区间、转换结果完全不一样,只是在 INT8 [-128,127] 场景下容易被人混用,非常容易踩通信协议大坑。

1、先明确两个公式

方案A:你现在代码写法(偏移128)

T = 128 + val;
hexstr = dec2hex(T,2);

映射关系:

T=val+128

适用区间:val ∈ [-128, 127]

  • val = -128 → T = 0
  • val = 0 → T = 128 (0x80)
  • val = 127 → T = 255 (0xFF)

这叫 Offset binary(偏移二进制码,偏置码),偏移量=128

方案B:之前 signed_hex 的标准补码算法

if val < 0
    T = val + 256;
end
hexstr = dec2hex(T,2);

8位有符号数二进制补码规则:

T={valval0val+28=val+256val<0

取值映射:

  • val = -128 → T = 128 (0x80)
  • val = 0 → T = 0 (0x00)
  • val = 127 → T = 127 (0x7F)

2、直接对比对照表(关键!INT8范围)

原始数值val 方案A val+128(偏移码) HEX 方案B val+256(8位补码) HEX
-128 0 00 128 80
-1 127 7F 255 FF
0 128 80 0 00
127 255 FF 127 7F

肉眼就能看到:同一个数值,输出的HEX完全不同,不能互相替换!

3、原理本质区别

(1)val + 256 → 真正二进制补码 INT8

和MCU、CAN报文、C语言 int8_t 内存存储格式完全一致
C语言:int8_t x = -1; 内存字节就是 0xFF,和 signed_hex 输出一模一样。
✅ 绝大多数汽车电控、嵌入式标准协议使用 补码

(2)val + 128 → 偏移二进制码

把 [-128,127] 平移到 [0,255],不是硬件原生补码
什么时候会用?
部分老协议、模拟量标定、标定文件(部分INCA标定报文、部分自定义协议)会自定义采用这种偏移编码。
⚠️ C语言char/int8_t不会原生存成这种格式
如果你发给单片机,单片机按正常int8解析,数据直接错乱!

4、举个直观例子

val = -1

  • +128:T=127 → 7F
  • +256:T=255 → FF

如果你的下位机期待收到补码 FF 代表-1,你发7F,下位机会解析成 127,数据彻底错误。

5、结合你现在的代码场景分析

你现有代码片段:

T=128+Accad_2K_Y(ii);        
Accad_2K_Save_Y(:,ii)=dec2hex(T,2);

等价于偏移二进制编码
而之前 encode_param(..., 'INT8') 使用的是二进制补码

重点提醒:

情况1:下位机协议规定【偏移128编码】

继续用 val+128

情况2:下位机是标准 int8_t 二进制补码(绝大多数车载ECU)

绝对不能用 +128,必须改用 signed_hex 的方式(负数+256)

6、延伸:为什么很多人会混淆两者?

两者都实现了:把[-128,127] 映射成0~255一个字节。
但是零点位置不一样

  • 补码:0 → 0x00
  • 偏移128:0 → 0x80

零点位置是区分两种编码最核心标志。

7、快速自测代码你可以直接运行

val = -1;
% 偏移128
disp(dec2hex(val+128,2));    % 7F
% 8位补码
if val<0
    disp(dec2hex(val+256,2));% FF
else
    disp(dec2hex(val,2));
end

额外工程建议(结合你做PPS/车载报文背景)

  1. 打开通信协议文档,搜索:
    • 如果写 int8 / two’s complement → 使用补码方案(+256)
    • 如果写 offset 128 / offset binary → 使用 val+128
  2. 千万不要凭经验混用,是车载报文最常见bug来源;
  3. 如果你需要,我可以帮你写一段统一兼容两种模式的转换函数,一键切换偏移码/补码。