1

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

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

4

1 回答 1

1

GCC 的分支覆盖率统计取决于机器代码级别的分支,而不仅仅是源代码中明确的分支(if/else、switch/case、for、while、||、&&、?:、...)。编译器通常必须插入额外的分支来实现语言特性,尤其是在 C++ 中:

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

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

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

根据您的质量要求,这是一个合理的位置。如果没有故障注入等先进技术,就不可能彻底测试所有机器代码分支。我个人建议不要忽略编译器插入的分支,因为它给人一种错误的安全感。

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

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

幸运的是,GCC 标记了为异常处理而添加的分支。自 gcovr 4.2(尚未发布)以来,您可以使用该gcov --exclude-throw-branches标志来忽略未发现的仅异常分支。这并不完美:它不仅排除了某些异常处理板的隐式分支,而且还排除了显式catch子句的分支。这可能会隐藏您确实想要测试的未覆盖的未覆盖。

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

于 2019-05-25T10:42:15.340 回答