配置表里写着 timeout=0x10,有人问:为什么超时是 16 秒,不是 10 秒?
前缀决定数值这件事平时没人注意,看错一次就是一次故障。下面每个结论都在对应运行环境里实测过(Node 20.19、Python 3.13、Java 17),输出就是真实结果。
坑一:0x10 和 10 之间差了 6
0x10 不是「10 的十六进制写法」,它是十六进制数 10,换算过来是十进制的 16:
| 写法 | 进制 | 十进制值 |
|---|---|---|
0x10 |
16 | 16 |
0b10 |
2 | 2 |
0o10 |
8 | 8 |
10 |
10 | 10 |
Python 3.13 实测:
>>> 0x10
16
>>> 0o10
8
>>> 0b10
2
记法很简单:0x 是 hex(十六进制)、0b 是 binary(二进制)、0o 是 octal(八进制)。看错前缀,值就差出好几倍。
坑二:前导零在老牌语言里是八进制
Java 实测:
int x = 010;
System.out.println(x); // 输出 8,不是 10
Integer.parseInt("010"); // 返回 10
同一个「010」:写成字面量走编译器的八进制规则,结果是 8;作为字符串解析默认按十进制,结果是 10。C、Java、老 JavaScript 都是这个规则。
Python 3 干脆禁止了这种写法,直接报错:
SyntaxError: leading zeros in decimal integer literals are not permitted;
use an 0o prefix for octal integers
教训:看到前导零的数字先问一句「这是几进制」,别默认是十进制。
坑三:parseInt 不带进制参数
Node 20 实测:
parseInt("08") // 8(ES5 起固定按十进制解析)
parseInt("0x10") // 16(0x 前缀仍会被识别成十六进制)
现在 parseInt("08") 返回 8,但老 IE 时代它返回 0——按八进制解析,8 不是合法的八进制数字,解析失败。「08 月」变「0 月」的 bug 当年坑过一大片日历组件。
习惯上永远写全第二个参数:parseInt("08", 10),把进制钉死,不给环境留解释权。
坑四:大数精度丢失,转回去都对不上
JavaScript 的 Number 是双精度浮点,安全整数只到 2^53 - 1。Node 20 实测:
Number(0x7FFFFFFFFFFFFFFF)
// 9223372036854776000 ← 原值是 9223372036854775807,末几位被抹掉了
Number(0x7FFFFFFFFFFFFFFF).toString(16)
// "8000000000000000" ← 转回十六进制连原值都对不上
Number("9007199254740993")
// 9007199254740992 ← 奇数变偶数
转 64 位 ID、长哈希片段这类大数时,浏览器里的 JS 工具会直接丢精度。要么用 BigInt,要么用后端换算——进制转换工具在后端用任意精度整数计算,0x7FFFFFFFFFFFFFFF 转出来就是精确的 9223372036854775807。
坑五:负数的十六进制,原码还是补码
Java 实测:
Integer.toHexString(-1) // "ffffffff",32 位补码
而数学意义上 -1 的十六进制写法是 -0x1。两种口径都对,但看协议文档时混起来就出错:协议里 0xFFFFFFFF 表示 -1 的补码,你拿 -1 去某些工具里转,得到的是 -1 或 -0x1 的原码形式。
先搞清楚对方用哪种口径,再对数值。
坑六:大小写与显示习惯
0xFF 和 0xff 是同一个数,但不同场景有不同惯例:MD5/SHA 摘要输出惯例是小写(详见 MD5/SHA 计算为什么不同机器结果不一样),配置文件和寄存器手册惯例是大写。
权限位也是进制的好例子:chmod 755 里的 7 = 二进制 111 = rwx,5 = 二进制 101 = r-x,每个数字对应一组权限位,更多权限组合见 Linux 命令速查。
小结
- 前缀决定数值:
0x10=16、0b10=2、0o10=8,别和 10 混 - 前导零在 C/Java 里是八进制字面量,Python 3 直接报错
parseInt永远带第二个参数- 超过 2^53 的数别用 JS Number 转,用 进制转换工具(后端任意精度)或 BigInt
- 负数的十六进制先确认是原码还是补码口径
配套 MD5/SHA 哈希工具 输出小写十六进制摘要,可以和进制转换对照着用。