进制转换是每个开发者绕不过的基础知识。颜色值 #FF0000 是十六进制,chmod 755 是八进制,网络协议抓包看到的字节序列是十六进制,CPU 的位运算是二进制。同一个数字,不同的写法,背后是同一个值。本文从原理出发,结合实际场景,帮你彻底搞懂进制转换。
四种进制的本质
所有进制系统都基于同一个规则:用有限的符号,通过”位值”(权重)来表示任意大的数。位值从右到左依次是基数的 0 次方、1 次方、2 次方……
十进制(Base 10)
日常使用的进制,符号 0–9。十进制 255 的展开:
2 × 10² + 5 × 10¹ + 5 × 10⁰ = 200 + 50 + 5 = 255
二进制(Base 2)
符号只有 0 和 1,是计算机硬件的原生语言。每一位代表一个 bit。
255 的二进制:11111111
展开:1×2⁷ + 1×2⁶ + … + 1×2⁰ = 128+64+32+16+8+4+2+1 = 255
八进制(Base 8)
符号 0–7,一位八进制等于三位二进制,是二进制的压缩表示。Linux/Unix 文件权限沿用至今。
755 的含义:
7 = 111 (rwx) — 所有者
5 = 101 (r-x) — 所属组
5 = 101 (r-x) — 其他人
十六进制(Base 16)
符号 0–9 + A–F,一位十六进制等于四位二进制(一个 nibble)。Web 颜色、内存地址、哈希值、MAC 地址都用十六进制表示,因为它对字节的表达最紧凑。
0xFF = 255
0x1A = 26
手算转换方法
十进制转其他进制:短除法
以十进制 42 转二进制为例:
42 ÷ 2 = 21 余 0
21 ÷ 2 = 10 余 1
10 ÷ 2 = 5 余 0
5 ÷ 2 = 2 余 1
2 ÷ 2 = 1 余 0
1 ÷ 2 = 0 余 1
余数从下往上读:101010,即 42₁₀ = 101010₂。
转十六进制时,直接用 16 做除数;转八进制用 8。
其他进制转十进制:位值展开
十六进制 2A 转十进制:
2A = 2 × 16¹ + 10 × 16⁰ = 32 + 10 = 42
八进制 52 转十进制:
52 = 5 × 8¹ + 2 × 8⁰ = 40 + 2 = 42
Python 进制转换
Python 内置支持最完整,直接上代码:
n = 255
# 十进制转其他进制
print(bin(n)) # '0b11111111'
print(oct(n)) # '0o377'
print(hex(n)) # '0xff'
# 去掉前缀,只要数字部分
print(format(n, 'b')) # '11111111'
print(format(n, 'o')) # '377'
print(format(n, 'x')) # 'ff'
print(format(n, 'X')) # 'FF'(大写)
print(format(n, '08b')) # '11111111'(补零到8位)
# 其他进制转十进制
print(int('11111111', 2)) # 255
print(int('377', 8)) # 255
print(int('ff', 16)) # 255
# 代码里直接写进制字面量
mask = 0b11110000 # 二进制字面量
perm = 0o755 # 八进制字面量
color = 0xFF5733 # 十六进制字面量
JavaScript 进制转换
const n = 255;
// 十进制转其他进制
n.toString(2); // "11111111"
n.toString(8); // "377"
n.toString(16); // "ff"
// 其他进制转十进制
parseInt("11111111", 2); // 255
parseInt("377", 8); // 255
parseInt("ff", 16); // 255
// 两个非十进制之间互转(先经过十进制中转)
function convertBase(value, from, to) {
return parseInt(value, from).toString(to);
}
convertBase("ff", 16, 2); // "11111111"
convertBase("755", 8, 2); // "111101101"
// 代码里直接写字面量
const mask = 0b11110000;
const perm = 0o755;
const red = 0xFF0000;
实际开发场景
Web 颜色:十六进制与 RGB 互转
CSS 颜色 #FF0000 是纯红色:R=255, G=0, B=0。设计工具给出的十六进制值,后端接口可能需要 RGB 整数,或者反过来。
def hex_to_rgb(hex_color):
hex_color = hex_color.lstrip('#')
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
def rgb_to_hex(r, g, b):
return f'#{r:02X}{g:02X}{b:02X}'
hex_to_rgb('#FF5733') # (255, 87, 51)
rgb_to_hex(255, 87, 51) # '#FF5733'
文件权限:八进制与 chmod
在 Python 脚本中修改文件权限,必须用八进制字面量,否则容易出错:
import os
import stat
# 设置 755 权限
os.chmod('deploy.sh', 0o755)
# 读取权限并转成八进制显示
mode = os.stat('deploy.sh').st_mode
print(oct(stat.S_IMODE(mode))) # '0o755'
常见权限值对照:
| 八进制 | 权限 | 典型用途 |
|---|---|---|
0o755 | rwxr-xr-x | 可执行脚本、目录 |
0o644 | rw-r—r— | 普通文件、配置 |
0o600 | rw------- | SSH 私钥、密钥文件 |
0o777 | rwxrwxrwx | 临时目录(慎用) |
网络协议:十六进制字节序列
抓包工具(Wireshark、tcpdump)显示的原始数据是十六进制。以太网帧的前 6 字节是目标 MAC 地址,格式如 FF:FF:FF:FF:FF:FF(广播地址)。
在 Python 中处理原始字节:
# 读取二进制文件的前16字节,十六进制显示
with open('data.bin', 'rb') as f:
header = f.read(16)
print(header.hex()) # '504b0304...'
print(' '.join(f'{b:02x}' for b in header)) # '50 4b 03 04 ...'
# 十六进制字符串转字节
raw = bytes.fromhex('504b0304')
位运算:二进制标志位
Redis、Linux 内核、网络协议大量使用位标志来压缩状态:
# 用位标志表示用户权限
READ = 0b001 # 1
WRITE = 0b010 # 2
DELETE = 0b100 # 4
user_perm = READ | WRITE # 0b011 = 3
has_read = bool(user_perm & READ) # True
has_delete = bool(user_perm & DELETE) # False
# 开启某个权限
user_perm |= DELETE # 0b111
# 关闭某个权限
user_perm &= ~WRITE # 0b101
在线进制转换
手算容易出错,写代码又嫌麻烦?ZeroTool 进制转换工具 支持二进制、八进制、十进制、十六进制实时互转,在任意一栏输入数值,其他栏立刻更新,无需提交,数据不离开浏览器。