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

如何避免gcc在编译后生成额外的代码?,gcc,code-coverage,gcov,gcovr,Gcc,Code Coverage,Gcov,Gcovr,我正在尝试使用“gcovr”获得代码覆盖率。我使用-O0作为优化级别。对于行覆盖,我得到了我需要的结果,但对于分支覆盖,不幸的是没有。根据以下内容,gcc在编译时会生成额外的代码,这会影响程序中的分支数。有没有办法告诉gcc不要生成额外的代码,或者至少生成尽可能少的代码 根据上面提到的答案,使用-O1有助于生成更少的额外代码,但对我没有任何好处。相反,我覆盖了更多的行(这是错误的),覆盖了更少的一个分支。GCC的分支覆盖率统计数据取决于机器代码级别的分支,而不仅仅是源代码中明确的分支(if/el

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


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

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分支
标志忽略未覆盖的仅异常分支。这并不完美:它不仅将隐式分支排除在某些异常处理板之外,还将分支排除在显式
catch
子句之外。这可能会隐藏您确实想要测试的未覆盖的内容


Gcovrs还提供了
--排除无法访问的分支
选项。如果分支覆盖率数据属于似乎不包含有用代码的行,则会删除这些数据。同样,这可能会排除重要的覆盖率数据,例如,如果多行语句的覆盖率归因于不包含有用代码的行。但是,这通常有助于排除由于静态变量而插入的分支。

切勿在生产代码中使用
-O0
-O1
,它们仅用于调试
-O2
-O3
更好,并且有很大的不同。做一个基准,看看他们带来的优势