在C++项目开发过程中,因为其为编译执行语言,语言规则要求较高,开发团队往往要花费大量的时间和精力发现并修改代码缺陷。所以C++静态代码分析工具能够帮助开发人员快速、有效的定位代码缺陷并及时纠正这些问题,从而极大地提高软件可靠性并节省开发成本。
以下为工具在付费价格、规则数量、准确率、扫描效率、编译依赖、IDE支持、跨平台支持、可扩展开发方面的对比数据。注:本次竞品分析的选择了3款游戏项目(约500万行代码)。
在可扩展性上,TSC有专人维护,定期根据用户需求扩展规则或新增功能特性,cppcheck和clang是开源工具,工具更新较慢,但如果用户有特殊需求可以自己扩展开发,pclint和coverity是商业软件,难以进行功能扩展。
三、检查规则大比拼
3.1规则大类
针对业内大量扫描工具在实际项目中扫描结果的影响比较,我们将代码质量问题分为以下几大类:
①致命类:可能导致程序宕机、无响应等影响范围极大的错误;
②逻辑类:可能造成程序不能达到预期逻辑结果的错误;
③编码规范及其他类:可能造成程序的可读性、可维护性较差的错误(不可达代码,无效的变量声明等);
3.2规则大类分布
根据3大影响分类,其严重程度分别为高、中、低,各类型规则数量分布为:
从规则分类占比来看:
①TSC针对
互联网产品高效开发修复原则,工具定位为针对致命和逻辑类问题,相对传统、军事、安全领域,并不关注编码规范及编译错误;
②coverity作为商业化软件,在付费后添加规则上,达到覆盖率最全面,除致命和逻辑类规则外,还有大量编码规范、安全和针对其他语言(如
java,C#)的规则;
③cppcheck作为开源工具,应用范围广泛,根据开源社区场景搜集,在各方面都有规则添加,但场景较为粗犷,场景虽多,但有效率不高。例如:cppcheck在初始化检查上有5个子规则,样本代码共扫描出312个问题,其中有效问题仅8个,有效率仅为3%。
④pclint作为商业化软件,在付费后添加规则上,达到覆盖率最全面,除致命和逻辑类规则外,还有大量编码规范、安全的规则;
⑤clang作为开源软件,规则较少,但规则类型分布较为均匀,在致命、逻辑类,还有编码规范、安全类都有规则添加。
3.3规则报错数量
整体规则数量上:pclint[915]>coverity[515]>cppcheck[245]>clang[74]>TSC[67]
可以看出pclint和coverity规则最多,TSC和clang规则最少,原因有如下3点:
①pclint和coverity作为商业化软件,需求来源于传统软件、军事、安全各个领域,其规则总数最多,其编码规范类规则数量分别高达646条和382条;排除掉低价值的编码规范类规则,规则数量排序为:pclint[269]>cppcheck[151]>coverity[133]>TSC[67]>clang[44]
②在规则实际报错数量上,以3款游戏500万行代码的结果覆盖度来看;
注:规则总数指工具所有的规则总数,报错规则数指开启工具所有规则情况下,扫描样本代码所覆盖的规则数量。
从实际项目扫描结果来看:
扫描出问题的规则数/规则总数:TSC[60%]>cppcheck[27%]>clang[19%]>coverity[10%]>pclint[9%]
pclint、coverity、cppcheck虽然规则数量很多,但因为其定制加入的大部分规则普遍适用度不高,大量规则可能在多个项目中都无法扫描出问题。有些规则却在多个项目中扫描出大量非核心的问题,如:函数没有被调用、未使用的变量、存在多余的头文件等。
③规则数量多来源于两个方面,一方面是规则覆盖更全面,另一方面是规则粒度划分得更细;
通过对具体规则进行分析,发现在规则划分粒度由细到出排序为[pclint,coverity,cppcheck,clang,TSC]
pclint和coverity划分粒度最细,cppcheck,clang次之,TSC最粗。
例如:coverity的除0报错分为整型除0,浮点数除0,取模除0;数组下标越界也细分为访问越界、读越界、写越界。Pclint和cppcheck初始化分为变量未初始化、结构体成员未初始化、类成员未初始化、string未初始化、data未初始化、union未初始化、全局静态变量未初始化等;而TSC则合并了一些过细的规则,未初始化上只分为变量未初始化和成员未初始化。
粒度划分越细既有优点也有缺点:
优点:可以针对细分规则灵活配置开关,关掉准确率低的规则
缺点:规则数量太多, 用户配置相当麻烦,新用户很难理解多个相似的规则之前的区别。
TSC为降低用户配置难度,在规则粒度划分上相对粗犷,但会从中提取出其中准确率低的场景,作为单独规则,从而达到可以关掉低准确率规则的目的。