进制转换是每个开发者绕不过的基础知识。颜色值 #FF0000 是十六进制,chmod 755 是八进制,网络协议抓包看到的字节序列是十六进制,CPU 的位运算是二进制。同一个数字,不同的写法,背后是同一个值。本文从原理出发,结合实际场景,帮你彻底搞懂进制转换。

在线进制转换工具 →

四种进制的本质

所有进制系统都基于同一个规则:用有限的符号,通过”位值”(权重)来表示任意大的数。位值从右到左依次是基数的 0 次方、1 次方、2 次方……

十进制(Base 10)

日常使用的进制,符号 0–9。十进制 255 的展开:

2 × 10² + 5 × 10¹ + 5 × 10⁰ = 200 + 50 + 5 = 255

二进制(Base 2)

符号只有 01,是计算机硬件的原生语言。每一位代表一个 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'

常见权限值对照:

八进制权限典型用途
0o755rwxr-xr-x可执行脚本、目录
0o644rw-r—r—普通文件、配置
0o600rw-------SSH 私钥、密钥文件
0o777rwxrwxrwx临时目录(慎用)

网络协议:十六进制字节序列

抓包工具(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 进制转换工具 支持二进制、八进制、十进制、十六进制实时互转,在任意一栏输入数值,其他栏立刻更新,无需提交,数据不离开浏览器。

立即使用进制转换工具 →