写代码的时候经常碰到各种进制的数字,CSS 里写颜色用十六进制 #ff5733,Linux 下改文件权限用八进制 chmod 755,位运算里看到的是一串 0 和 1。这些不是随便定的规矩,不同进制在不同场景下有各自的用处。下面把常用的几种进制、它们的应用场景和互相转换的方法整理一下。

各种进制在编程里的实际用途

二进制(Base 2)

计算机底层就是靠 0 和 1 存数据的。平时写代码直接用二进制的情况不多,但位运算的时候会接触到。比如权限系统里用一个整数的每个 bit 表示一种权限,读权限是第 0 位(0b0001),写权限是第 1 位(0b0010),执行权限是第 2 位(0b0100)。Linux 文件权限的 rwxr-xr-x 本质上就是三组三位二进制数。

八进制(Base 8)

八进制现在用得最多的地方就是 Linux/Unix 的文件权限。你肯定见过 chmod 644 或者 chmod 755 这样的命令。这里每个数字代表一组权限(文件所有者/同组用户/其他用户),数字范围 0-7,正好对应三个 bit。比如 7 就是 111(读写执行都有),5 是 101(读和执行),4 是 100(只有读)。JavaScript 里用 0o 前缀表示八进制字面量。

十进制(Base 10)

这个不用多说,日常用的计数方式。编程语言里默认的数字字面量都是十进制。

十六进制(Base 16)

出现频率很高。CSS 颜色值 #RRGGBB 用两个十六进制数表示一个颜色通道(00 到 ff 对应 0 到 255)。内存地址、网络协议里也常用十六进制表示字节值,因为一个字节恰好可以用两个十六进制字符完整表达(0x00 到 0xFF)。比二进制紧凑,比十进制更贴近字节边界。

Base36 / Base62

短链接服务(比如 t.cn/xxxx)用的编码方式类似 Base36 或 Base62。原理是把一个长数字 ID 用更多的字符(0-9 加 a-z 甚至大小写字母)来表示,结果更短。这个在 URL 缩短、邀请码生成这类场景会用到。

手动怎么做进制转换

从十进制转到其他进制,通用方法是除基取余。以十进制 255 转十六进制为例:

  • 255 ÷ 16 = 15 余 15(对应 F)
  • 15 ÷ 16 = 0 余 15(对应 F)
  • 余数倒序排列:FF

所以 255 的十六进制是 0xFF。转二进制也一样,除 2 取余就行:

  • 255 ÷ 2 = 127 余 1
  • 127 ÷ 2 = 63 余 1
  • 63 ÷ 2 = 31 余 1
  • ...一直除到商为 0
  • 结果:11111111

反向操作(其他进制转十进制)用的是按权展开。比如十六进制 1A3 转十进制:1×16² + 10×16¹ + 3×16⁰ = 256 + 160 + 3 = 419

实际工作中很少手算,知道原理就行。但面试偶尔会问到,心里有个数不至于懵。

各语言的内置转换函数

日常开发直接调库函数就够了:

// JavaScript
parseInt("FF", 16)          // 字符串 → 十进制
(255).toString(16)          // 数字 → 十六进制字符串
(255).toString(2)           // 数字 → 二进制字符串
(255).toString(8)           // 数字 → 八进制字符串

// Python
int("FF", 16)               # 字符串 → 十进制
hex(255)                    # → '0xff'
bin(255)                    # → '0b11111111'
oct(255)                    # → '0o377'

// Java
Integer.parseInt("FF", 16)
Integer.toHexString(255)
Integer.toBinaryString(255)

// C
strtol("FF", NULL, 16)      // 字符串 → 长整数
sprintf(buf, "%x", 255);    // 输出十六进制
sprintf(buf, "%o", 255);    // 输出八进制

大部分语言的模式都差不多:输入接受一个基数参数(radix/base),输出提供 toXxx 方法或格式化函数。

进制转换有哪些常见错误

大小写问题:十六进制的 A-F 和 a-f 在数值上是等价的(0xFF 等于 0xff),但在某些场景下需要统一格式。比如 CSS 颜色虽然不区分大小写,但团队规范可能要求全小写。parseInt 函数一般都能处理两种情况。

前缀混淆:不同语言的前缀不一样。JS 用 0x 表示十六进制、0b 表示二进制、0o 表示八进制;Python 2 用 0 开头表示八进制(容易跟十进制混淆),Python 3 改成了 0o;C/C++ 也用 0x0 前缀。复制粘贴代码的时候注意前缀别漏掉。

精度丢失:JavaScript 的 Number 类型是 IEEE 754 双精度浮点数,能精确表示的最大安全整数是 2^53 - 1(9007199254740991)。超过这个值的整数做进制转换可能会丢精度。如果处理超大整数得用 BigInt。

负数处理:大多数语言的 toString(radix) 方法对负数会保留负号然后转换绝对值部分。但在某些底层场景下(比如补码表示),负数的二进制形式跟你直觉想的不一样,需要注意。

遇到拿不准的,丢到在线工具里验证一下结果比自己猜靠谱。

常见问题

十六进制里的字母大小写有区别吗?

没有区别。十六进制中 A-F 和 a-f 表示相同的值(10-15)。大多数编程语言的转换函数两种写法都接受。但出于代码规范,建议统一用大写或小写,团队里保持一致。

二进制转十进制怎么快速算?

从右往左,每一位的值乘以 2 的 n 次方(n 从 0 开始),然后全部相加。比如 1011 = 1×8 + 0×4 + 1×2 + 1×1 = 11。熟练了以后可以直接看:有 1 的位置对应的权值加起来就是结果。

为什么编程里常用十六进制?

因为十六进制和二进制是 4 对 1 的关系,一个十六进制位正好对应四个二进制位。比二进制短 4 倍,读写都方便。颜色值、内存地址、MAC 地址等场景几乎全用十六进制。