许多人认为,如果源代码编译干净,激活所有警告,那么它就可以进入验证阶段,例如测试或代码审查。但是,假设如果代码已干净地编译,那么存在的任何错误一定是由对需求的解释而不是它们的实现引起的,这是危险的。Wojciech对这一假设进行了实证评估,并证明与专用静态分析和编码标准执行(CSE)工具生成的警告范围相比,任何编译器提供的警告范围都非常有限。
一种普遍的观点是,如果源代码编译干净,所有警告都打开,那么它就可以进行验证,例如测试或代码审查。这种假设的危险在于,如果代码已经编译干净,那么存在的任何错误都必须在需求的解释中,而不是在它们的实现中。然而,对这一假设的实证评估最终表明,与专用静态分析和编码标准执行(CSE)工具生成的警告范围相比,任何编译器提供的警告范围都受到严重限制。
本文的比较使用了GNU Common C++“2”版本1.6.3,这是一个大约42,000行代码的真实代码库。由于这是一个跨平台库,因此它不支持任何特定的编译器,并且可以用作任何编译器可能期望处理的代表性示例。其适中的大小允许手动检查所有编译器警告的准确性,同时确保其多样性和数量不平凡。
检查的四个编译器是GCC,Visual C++,C++Builder和Intel C++ Compiler,以及静态分析和CSE工具,表明如果开发人员过于依赖编译器来识别编码缺陷,他们可能会发现他们的代码不可维护,可重用或可移植。此外,Visual C++“团队版”使用“代码分析”功能补充其标准编译器警告,其输出包含在这些结果中。
生成警告输出
在实践中,这四个编译器中有一个遗漏的每一个缺陷都会对代码库的质量产生影响,无论是可维护性、可移植性还是可重用性。这在部署代码时是一个重大威胁,尽管大多数示例源代码都通过了编译器的架构检查参数。
由于这些编译器基于不同的前端,因此每个编译器可能会发出不同的警告。表 1 并排比较了每个编译器和静态分析工具生成的不同警告,用于我们比较中使用的代码库:GNU Common C++ “2”。使用编译结果时可用的每个编译器的最新版本,并启用最大警告级别。(表 1 的标题行指示使用的确切编译器版本和选项。不是相对于这些编译器进行基准测试,而是将它们的警告输出与静态分析器进行比较以进行C++。
表 1:默认检测比较 – 比较的基础和每个百分比数字是编译器和给定类别中的静态分析工具报告的不同警告之间的比率。标题行详细说明了用于启用最大警告级别的确切编译器版本和选项。
如表中最后一行所示,CSE 工具生成了超过 400 个警告,而测试的编译器甚至没有一个设法返回 20 个警告。事实上,根据经验,静态分析识别的警告是所有四个编译器中最好的 25 倍 - 启用了代码分析的可视化C++(/analyze 选项)。值得注意的是,如果未启用此功能,Visual C++ 在所有测试的编译器中生成的警告最少。
表 1 中的第一列数据显示了静态分析工具也检测到的每个编译器生成的警告的百分比。请注意,重叠程度很高,平均 84% 的编译器警告由 CSE 工具复制。比较的这一面只是为了完整性,因为无论是否执行静态分析,开发人员都需要启用编译器警告。
表 1 的其余行显示了比较的另一面:编译器标记了多少静态可检测的内容?很明显,编译器警告避开了“C++的效率和使用”类别。这是意料之中的,因为编译器优化是在后端执行的,通常是静默的。但是,值得注意的是,专用的 CSE 工具在此类别中有一系列检查,专注于低效设计,与低级编译器优化不同,这些检查无法自动纠正。
错过的常见警告
可移植性是编译器库中缺少的常见警告类别。只有 C++Builder 生成了一个可归类为可移植性问题的警告,而静态分析工具标记了 17 个警告。这些表示符合 ISO C++ 语言定义的构造,但可能会导致不同的编译器实现出现问题。编译器供应商通过提供 ISO C++ 的扩展来锁定开发人员的情况并不少见,可移植性在他们的议程上并不重要也就不足为奇了。这代表了可移植性问题的另一个方面,即符合 ISO C++,这可以通过静态分析工具中的单独警告类别来解决。
对于大多数编译器供应商来说,ISO C++合规性归结为接受尽可能多的有效C++代码,同时回避检测不一致代码的问题 - 通常是他们自己的语言扩展。检测 ISO C++不合格是 CSE 工具的优势之一,这在表 1 中很明显。很明显,大多数编译器警告可以归类为(代码)“设计问题”和“可维护性”,其中一些警告非常小,值得将它们降级为样式问题。然而,即使对于这些重点领域,与静态分析工具相比,其覆盖率也远非全面,对于最佳竞争者 - 具有代码分析功能的可视化C++,覆盖率为7%。
编译器传统上避免的其他警告类别包括:命名约定、代码布局、复杂性指标阈值以及禁止某些关键字(例如 throw)和函数(例如 malloc),但 Visual C++ 代码分析功能有一个明显的例外,该功能具有硬连线警告,用于使用 _alloca、_snprintf 和 TerminateThread 函数。由于这不如静态分析工具的可配置检查(允许指定任何函数)全面,因此获得了半分,使该编译器在本地(公司特定)标准执行方面得分为 10%。实施上述区域的主要好处是增强了代码的可重用性,从表 1 中可以明显看出,编译器实际上尚未利用这一点。
在比较每个工具生成的实际警告实例时,将原始警告计数制成表格并不是特别有启发性,因此常见的C++编码标准将作为比较的客观基础。从表 2 可以看出,与 CSE 工具记录的违规行为相比,没有一个编译器提供任何明显的高完整性C++、JSF++ 或 MISRA C++ 强制实施。
表 2:编码标准执行 (CSE) 比较
全面性教育工具:最全面/可转移的路线
一个常见的误解是,编译器警告是静态分析源代码的充分方法。与专用的静态分析和 CSE 工具(如 PRQA 的 QA•C++)相比,市场领先的编译器提供的警告范围有限。此外,可用的少数检查往往集中在代码错误行为和可维护性问题上,而可重用性和可移植性问题完全被忽视。专用的 CSE 工具提供了所有这些领域的全面实施,同时保持编译器不可知性,因此代码库和开发环境不必局限于特定的编译器和平台。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !