如何称量代码复杂度(C++/C#)

微博上的蛙蛙王子提出三个设想,发送给微博上一些知名程序员,惊悚的是,这三个问题我以前也考虑过还动手做过。这是巧合呢?还是巧合涅?

蛙蛙王子的问题是:是否有个工具可以检测出函数的长度?检测出函数中嵌套的层次?是否可以检测出重复代码?

基于我在罗克韦尔时写的一个Lua脚本经验来看,第一第二个问题非常容易。第三个问题稍有麻烦,有工具或者开源项目能做到,但是效果一般。

回到标题上的问题,称量代码复杂度,可以通过实现某个工具检测长度或者嵌套层次来完成,还有另外更简单的办法。

通常情况下,复杂代码所在文件大小也会比其他文件大出不少,所以不用编写什么工具,只要逐个察看项目中个头比较大的文件,就可以找到代码味道不好的地方了。

另外一个办法是通过版本控制工具,什么样的文件需要重构?基本上修改check in 次数多的文件,你要考虑重构了,即使代码味道不错,也肯定是责任过重,这个办法也很简单,把history导出统计一下就可以了。

如果通过判断函数长度和嵌套层次,建议大家可以这样实现,我考虑过C++的实现,算是比较完整,不需要什么编译原理知识。

函数长度和嵌套层次可以这样判断。前提1,我们可以确定C++中的{}成对出现;前提2,class可以通过关键字定位,而struct可以假定其中没有函数体,不需要判断;前提3,函数中的{}也一定是成对出现。至于其他的复杂问题,我觉得没必要考虑太多,除非你想做一个商用级别的软件,否则一个Python脚本就能搞定。

基于这些前提我们可以这样实现,先清理注释部分,C++注释分成// /*,另外对于/*要考虑单行和多行,基本上就是按行处理就行了。之所以这样,是为了防止注释部分包含{}或者特定关键字。

如果能找到class,判断类名,然后查找{。对于{}匹配,可以定义一个树形结构,函数或者类作为根,发现一个{,加入一层嵌套,发现一个},减去一层嵌套。如果嵌套层次为零(不在class定义体中),或者为一(在class定义体中,假定class的{}级别为0),那就是函数,稍微处理一下(),就能拿到参数,然后前面就是函数名字了。

这样按照文件处理逐个处理完,就能判断出那些函数,函数体多长,嵌套层次如何了。

针对C#,也可以这样处理,但是我猜测如果用Roslyn有更好的办法,可是没找到例子。

————-

另外一个问题是重复代码。有一些链接,比如 http://en.wikipedia.org/wiki/Duplicate_code http://pmd.sourceforge.net/cpd.html http://checkstyle.sourceforge.net/config_duplicates.html http://patterninsight.com/products/clone-detection/ http://stackoverflow.com/questions/546487/tools-to-identify-code-duplications

但是我感觉最好用的办法,是通过peer code review来检查,因为这一块对于算法而言,应该是实现难度挺大的,而且结果也不理想,review的方式基本上可以杜绝类似问题。我们之所以不用review方式解决代码长度和嵌套层次,是因为的确有办法实现。

 

《如何称量代码复杂度(C++/C#)》有1个想法

发表评论