C++小知识:不要去做编译器的工作
对于C++编程的老鸟来说,有时候他们喜欢把一些东西按照编译器的工作原理进行改写,以便提高代码的运行效率。这么做确实高明,也能体现出程序员的水平,但是这么做也是有风险的。因为有时候你可能会因为一些简单的笔误,而造成非常难以察觉的错误。本文就给出了类似的例子。
这个Bug出现在MySQL源代码中。
错误代码:
staticintrr_cmp(uchar*a,uchar*b) { if(a[0]!=b[0]) return(int)a[0]-(int)b[0]; if(a[1]!=b[1]) return(int)a[1]-(int)b[1]; if(a[2]!=b[2]) return(int)a[2]-(int)b[2]; if(a[3]!=b[3]) return(int)a[3]-(int)b[3]; if(a[4]!=b[4]) return(int)a[4]-(int)b[4]; if(a[5]!=b[5]) return(int)a[1]-(int)b[5];<<<<==== if(a[6]!=b[6]) return(int)a[6]-(int)b[6]; return(int)a[7]-(int)b[7]; }
说明:
这是一个在对代码段进行拷贝粘贴时出现的典型错误。程序员很可能是把“if(a[1]!=b[1])(int)a[1]–(int)b[1];”这段代码拷贝了好几遍(然后手动改数组下标),用来实现一个循环。不过程序员忘记把其中某一行的数组下标1改成5。结果就是函数有时候能返回正确的值(,有的时候则不行),这种错误是很难侦测的。事实上这个错误的确很难捕捉,在我们用PVS-Studio扫描MySQL源代码之前,所有其他的测试都没能发现这个错误。
正确的代码:
if(a[5]!=b[5]) return(int)a[5]-(int)b[5];
尽管之前的代码看上去整洁易读,但是程序员还是很有可能漏看这个错误。因为这个代码块的内部结构很相似,所以你本能地会一扫而过,而不会特别集中注意力去阅读代码。
之所以把代码写成这样,很可能是程序员想尽可能地优化代码。他(或她)想手动“展开循环”(来进行优化)。不过我想在这儿可不是个好主意。
首先,我很怀疑程序员是不是真的能通过这种方法达到效果。要知道,现代编译器已经相当智能了,如果真的能优化程序性能,(编译器)自动就会完成展开循环的优化。
其次,由于尝试进行优化却造成了代码中出现bug。如果程序员一开始能老老实实写一个简单循环,那么犯错误的几率就会降低很多。
我建议把这个方法写成这样:
staticintrr_cmp(uchar*a,uchar*b) { for(size_ti=0;i<7;++i) { if(a[i]!=b[i]) returna[i]-b[i]; } returna[7]-b[7]; }
这种写法有两个优势:
- 1.这个函数更容易阅读和理解。
- 2.编写代码时,降低犯错几率。
至于性能方面,我敢说这个版本不会比之前写得很长的那个版本慢。
这个推荐的方法实际上表达了下面的意思:代码要简单易读。简单的代码通常即是正确的代码。不要去做编译器的工作——例如,(手动)展开循环。编译器很明确知道自己该做什么,并不需要你的帮助。手动代码优化工作只针对某些特定的关键代码,而且只在分析器已经确认这些代码是瓶颈以后,才可能恰当。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。如果你想了解更多相关内容请查看下面相关链接