判断字符是否为数字的哪种C语言代码实现速度最快?
我有两个判断字符是否为数字的C语言函数,想知道哪种实现速度更快:
第一种实现:
bool isDigit(char c){ uint8_t num = c - '0'; if(num >= 0 && num <= 9) return true; return false; }
第二种实现:
bool isDigit(char c){ switch(c - '0'){ case 0: return true; case 1: return true; case 2: return true; case 3: return true; case 4: return true; case 5: return true; case 6: return true; case 7: return true; case 8: return true; case 9: return true; default: return false; } }
之前看到资料说switch比if更快,但仔细想下来,第二种代码看起来要逐个匹配case直到找到符合项,而第一种只需要两次比较,所以想搞清楚到底哪种更快。
先澄清一个常见误区:switch不一定是逐个匹配
现代编译器会对连续的case值做优化,比如把第二种实现转换成跳转表(jump table)——编译器会生成一个数组,每个元素对应case的跳转地址,执行时直接用c-'0'的结果作为索引,跳转到对应的代码块(直接返回true),如果索引超出0-9的范围,就跳转到default返回false。这种情况下,switch的执行是O(1)的,和数组索引一样快,完全没有逐个匹配的过程。
两种实现的性能对比
开启编译器优化时(比如
-O2或-O3):
编译器会把这两个函数都优化到极致——第一种的num >=0 && num <=9会被简化成num <=9(因为uint8_t本身就是无符号类型,不可能小于0),甚至直接生成范围判断的机器指令;第二种会被转换成跳转表或者和第一种类似的范围判断逻辑。最终两者生成的机器码可能几乎完全一致,性能没有差别。未开启优化时:
第一种只需要一次减法+两次比较(实际编译器可能合并成一次范围比较),而第二种会变成逐个case的条件判断(比如对0到9依次做相等比较),这时候对于字符'9',需要匹配10次才会返回,确实比第一种慢。
实际开发中的选择
这种极小的函数,编译器通常会自动做内联优化,把函数代码直接插入到调用的地方,性能差异可以忽略不计。这时候更应该优先考虑可读性:第一种代码简洁、逻辑清晰,维护成本低;第二种代码冗余,除了特殊场景(比如极端受限环境下的手动优化),完全没有必要使用。
额外注意点
第一种实现里用了uint8_t,需要注意char的符号性:如果你的编译器默认char是有符号类型,当输入字符的ASCII值小于'0'(比如0x7F之后的扩展字符),c-'0'会得到负数,转换成uint8_t后会变成一个大于127的无符号数,这时候num <=9的判断依然正确,不会影响结果。如果直接用char类型做判断,c-'0'可能为负数,这时候num >=0的判断就有意义了——不过编译器同样会优化掉多余的判断。
内容的提问来源于stack exchange,提问作者Daniel Muñoz

