你写过 scanf("%d") 的底层实现吗?musl libc 用一个 __intscan 函数,在150行内搞定了任意进制、自动检测、溢出安全的完整整数解析。本文逐层拆解每个技巧。
0x00 函数签名
unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim)
- base:进制(0=自动,2-36)
- lim:上限值,最低bit编码了有符号/无符号语义
- 返回解析结果,溢出时返回 lim 或 lim-1,并设 errno=ERANGE
0x01 技巧1:256字节查找表
static const unsigned char table[] = { -1, -1, …, 0,1,2,…9, -1,…, 10,11,…35, … };
256字节直接映射,table['0']=0,table['A']=10,table['z']=35,其他为-1。
查表 vs if-else:查表无分支,在热点循环中快30%+。
0x02 技巧2:双阶段解析防溢出
unsigned x; // 第一阶段:32位
unsigned long long y; // 第二阶段:64位
先用32位跑,安全后转64位继续。关键不等式:
y <= ULLONG_MAX/10 && 10*y <= ULLONG_MAX – (c-'0')
等价于 y*10+digit <= ULLONG_MAX,但先判断再计算,永不溢出。
0x03 技巧3:三条优化路径
| 10 | 不查表,c-'0' 减法 | c-'0'<10U |
| 2的幂 | 移位代替乘法 | x<<bs | val[c] |
| 其他 | 查表+乘法 | x*base+val[c] |
2的幂的移位位数用魔法数字表计算:
int bs = "\\0\\1\\2\\4\\7\\3\\6\\5"[(0x17*base)>>5&7];
(0x17*base)>>5 & 7 等价于 log2(base),零分支。
0x04 技巧4:自动进制检测
if (c=='0') {
c = shgetc(f);
if ((c|32)=='x') base=16; // 0x
else if (base==0) base=8; // 0开头→八进制
}
c|32 一次比较覆盖 x 和 X。
0x05 技巧5:无分支符号处理
return (y^neg)-neg;
- neg=0:y^0-0 = y
- neg=-1:y^-1-(-1) = ~y+1 = -y
等价于 neg ? -y : y,但没有if。
0x06 完整流程
跳空白 → 读符号 → 检测0x/0前缀 → 双阶段解析
→ 溢出则吞掉剩余数字 → 回退字符 → 按lim奇偶性返回
写在最后
这段代码是工程级优化的教科书:查表、双阶段、无分支、位运算hack,每个技巧都能直接复用到你自己的项目中。
完整代码在 musl libc 的 src/stdio/__intscan.c,建议clone下来单步调试。
这段代码的设计哲学:用最小的代码量,覆盖最多的边界情况,同时保持最高的执行效率。每个技巧都不是炫技,而是实打实的性能需求驱动的。

