如何避免gcc在编译后生成额外的代码?

时间:2019-05-24 09:22:06

标签: gcc code-coverage gcov gcovr

我正在尝试使用“ gcovr”获得代码覆盖率。我正在使用-O0作为优化级别。对于线路覆盖,我得到了所需的结果,但是对于分支覆盖而言,不幸的是没有。根据以下answer,gcc在编译时会生成额外的代码,这会影响程序中的分支数量。有没有办法告诉gcc不要生成额外的代码,或者至少不要生成更少的代码?

根据提到的答案,使用-O1有助于减少额外的代码,但这并没有给我带来任何好处。相反,我覆盖了更多行(这是错误的),而分支覆盖得较少。

1 个答案:

答案 0 :(得分:1)

GCC的分支覆盖范围统计信息取决于机器代码级别的分支,而不仅取决于源代码中显式的分支(if / else,switch / case,for | while,||,&&&,?:,…)。编译器通常必须插入额外的分支才能实现语言功能,尤其是在C ++中:

  • 静态初始化(C和C ++)
  • 析构子
  • 异常处理
  • 安全检查,例如绑定检查(通常不使用)

如果允许GCC进行优化,则可能可以消除其中的一些分支。这就是为什么使用-O1有时可以帮助覆盖数据的原因。另一方面,这使gcov很难将coverage数据归因于正确的源代码行。

理论上可以采用所有机器代码分支。如果未发现这些分支之一,则表示状态未经测试。从编译器的角度来看,if语句或调用可以抛出的函数之间没有太大区别。但是对于您来说,这些并不等效:您可能只对测试显式分支感兴趣。

根据您的质量要求,采取适当的位置。如果没有诸如故障注入之类的先进技术,就不可能对所有机器代码分支进行详尽的测试。我个人建议不要忽略编译器插入的分支,因为它会带来错误的安全感。

因此,我们必须接受50%的分支覆盖率是免费的,而不仅仅是良好的语句覆盖率,但是100%的分支覆盖率是无法实现的。在C ++的上下文中,分支覆盖率可能是查看逐行覆盖率的最佳方法,而不是作为汇总统计信息。

GCC确实允许您使用-fno-exceptions标志来编译软件而无需进行异常处理。该过程将直接中止而不是引发异常。但这有效地将您切换到了不兼容的C ++方言。尝试/捕获之类的东西将不再起作用。在标准库中进行错误检查更改。因此,仅出于代码覆盖目的,您就不能无例外地编译软件。

幸运的是,GCC标记了为异常处理添加的分支。从gcovr 4.2(尚未发布)开始,您可以使用gcov --exclude-throw-branches标志忽略未发现的仅异常分支。这不是完美的:它不仅将隐式分支排除在某些异常处理区之外,还分支到显式的catch子句。这可能会隐藏您想要测试的未发现的发现。

Gcovrs还提供了--exclude-unreachable-branches选项。如果分支覆盖率数据归因于似乎不包含有用代码的行,则这将删除它们。同样,这可能会排除重要的覆盖率数据,例如,如果多行语句的覆盖率归因于不包含有用代码的行。但是,这确实有助于排除由于静态变量而插入的分支。