杂记 › 技术笔记 › 二进制、十六进制总是算不对?2/8/10/16进制互转方法

二进制、十六进制总是算不对?2/8/10/16进制互转方法

上个月排查一台上报告警的工控机。日志里那行写的是 alarm=0x0E12,我扫了一眼,把 E12 当十进制读成了"三千六百一十二",又拿文档里的位定义表从 bit0 数到 bit12,对上了一个根本不存在的项目,围着错误的方向查了大半天。后来把 0x0E12 展开成 0000 1110 0001 0010才看清:置 1 的是 bit1、bit4、bit9、bit10、bit11,加起来是 2+16+512+1024+2048 = 3602,跟"3612"差的就是我把十六进制的 1 当成十位那一格。值从来没变,变的只是写法。

一、进制只是同一个数换一种写法

一个数值确定之后,用几个数码去书写它是可以选的。基数决定了每一位能放几个符号、以及进一位乘几。

进制基数数码代码里的前缀你会在哪见到
二进制20 10b位运算、寄存器、掩码
八进制80-70o(老写法是前导 0)Linux 权限 chmod 755
十进制100-9无日常、日志里的计数值
十六进制160-9 A-F0x颜色、内存地址、协议字节流

十六进制之所以在工程里到处是,是因为它和二进制是 4 位一组的整倍数关系:1 个十六进制位正好压住 4 个二进制位,人看一眼 0xFF 就知道那是 8 位全 1。

二、手算只需要三招

  • 十进制转别的:反复除以基数取余数,余数倒着排。以 3756 转十六进制为例:3756 ÷ 16 = 234 余 12(C),234 ÷ 16 = 14 余 10(A),14 ÷ 16 = 0 余 14(E),倒排得 0xEAC。
  • 别的转十进制:按位权展开。EAC = 14×256 + 10×16 + 12 = 3756,能回到原值说明上一步没写错。
  • 二进制 ↔ 十六进制:从右往左每 4 位切一刀,逐组查表。3756 的二进制是 1110 1010 1100,三组分别是 E、A、C。

顺便验证一个不常见的:12345678 用 36 进制(0-9 加 A-Z)写出来是 7CLZI,按权展开 7×36⁴ + 12×36³ + 21×36² + 35×36 + 18 = 11757312 + 559872 + 27216 + 1260 + 18 = 12345678,正好还原。短链、订单后缀那类"字母数字混合码"基本都是 36 进制。

三、常碰到的那几个数,记住比现场换算快

十进制二进制十六进制八进制典型出处
2551111 1111FF377RGB 单通道上限、8 位全 1
4201101001001A4644chmod 644 的真实数值
4931111011011ED755chmod 755 的真实数值
40961 0000 0000 0000 0000100010000一页内存的字节数
6553516 个 1FFFF177777端口号上限、无符号 16 位
1677721524 个 1FFFFFF7777777724 位色的白 #FFFFFF
214748364731 个 17FFFFFFF1777777777732 位有符号整数上限,接口溢出的报错值
429496729532 个 1FFFFFFFF37777777777无符号 32 位、IPv4 广播地址

八进制那一列有个实用结论:755 和 493 是同一个权限的两种写法。配置文件里存哪个都行,怕的是混着用——我看到过同一段脚本一处写 755、一处写 493,diff 里像改了两遍。

四、我现在实际怎么处理

  1. 先把日志里的原始写法照抄下来,保留 0x、0b 前缀,不要凭记忆重敲,E12 那种事故一半来自手抄。
  2. 数值本身我会用进制转换器算:选好源进制,二、八、十、十六的结果同屏给出,省掉我一边按计算器一边对齐位数。位掩码要逐位勾的时候,我盯的是那个二进制输出,不是十六进制。
  3. 字节流要按字符看的时候用它另一个方向:文本转成每个字符的进制编码,A1 会得到 41 31,分隔符可选,抓包时对照协议表逐字节核。
  4. 颜色那种六位十六进制我不再手拆。以前把 #FF8A00 拆成三段再除 255,经常漏掉进位,直接用颜色转换把 HEX 和 RGB、HSL 对齐更省事。

如果只是想统一文本里的全角半角或看 ASCII 值,文本编码转换更对口,它管的是字符层面,不是数值进制。

五、容易踩的三处

前缀和默认基数不一致。JavaScript 里 parseInt('0755') 得到 755,parseInt('0755', 8) 才是 493;而字面量 0755 在严格模式和 ES Module 下直接抛 SyntaxError,八进制必须写 0o755。同一份权限值,三种写法三种结果,跨语言传配置时务必写全基数。

大数会先丢精度再谈进制。双精度浮点只能精确表示到 2⁵³−1 = 9007199254740991,再往上 9007199254740993 会被存成 ...992。这类数换算前得确认工具按 BigInt 走,否则十六进制看着正常、尾数已经错了。

负数没有"标准十六进制"。-1 写成 FFFFFFFF 只在 32 位补码这个前提下成立,换 16 位就是 FFFF。进制转换处理的是数值本身,位宽要自己带上。

六、常见疑问

Q:为什么计算机非要用二进制?

物理上两个状态最稳(高电平低电平),抗噪和实现成本都最低。八进制、十六进制不是给机器用的,是把几十个 01 压缩成人眼能扫的写法。

Q:十六进制小数怎么转?

整数除基取余,小数是乘基取整:0.5 × 16 = 8.0,所以 0.5 写成 0.8。但 0.1 在任何以 2 为基的进制下都是无限循环的,这正是浮点误差的来源之一,别指望换一种进制能消掉它。

Q:0xFF 和字符串 "FF" 有区别吗?

有。前者是数值字面量,后者是文本,要显式按 16 进制解析才能得到 255。日志、JSON、配置文件里的"十六进制"几乎都是字符串形态,这就是很多换算错位的起点。

Q:为什么最多到 36 进制?

36 刚好是 10 个数字加 26 个字母。再往上要引入大小写区分(62 进制)或其他符号,可读性和不区分大小写的场景都会出问题。

Q:位掩码怎么核对有没有多勾一位?

把合计值转回二进制,逐位和文档表对齐;两边位序(从 0 还是从 1 起数)确认一次。我做的是把 3602 展开成 0000 1110 0001 0010 对着表打勾,比反向把位值加起来更容易发现多出的那一位。

那台上报 0x0E12 的机器最后确认是编码器异常加电机过温同时触发,跟进制没关系。但它让我改掉一个习惯:凡是带 0x、0o 的值,一律展开成二进制或十进制写在注释里,不靠脑内换算。人的十进制直觉是唯一会出错的那一环。

📎 相关文章

大小写、驼峰、下划线命名混乱?批量互转的方法 2026-10-15 这个IP是哪里的?归属地和运营商怎么查、能查到什么 2026-10-15 压缩成一行的JS看不懂?在线美化、格式化代码 2026-10-15 \u4e2d是什么鬼?中文与Unicode编码在线互转 2026-10-15 接口返回的JSON怎么变成表格?在线转Excel/CSV一步到位 2026-10-15