如何避免gcc在编译后生成额外的代码?
我正在尝试使用“gcovr”获得代码覆盖率。我使用如何避免gcc在编译后生成额外的代码?,gcc,code-coverage,gcov,gcovr,Gcc,Code Coverage,Gcov,Gcovr,我正在尝试使用“gcovr”获得代码覆盖率。我使用-O0作为优化级别。对于行覆盖,我得到了我需要的结果,但对于分支覆盖,不幸的是没有。根据以下内容,gcc在编译时会生成额外的代码,这会影响程序中的分支数。有没有办法告诉gcc不要生成额外的代码,或者至少生成尽可能少的代码 根据上面提到的答案,使用-O1有助于生成更少的额外代码,但对我没有任何好处。相反,我覆盖了更多的行(这是错误的),覆盖了更少的一个分支。GCC的分支覆盖率统计数据取决于机器代码级别的分支,而不仅仅是源代码中明确的分支(if/el
-O0
作为优化级别。对于行覆盖,我得到了我需要的结果,但对于分支覆盖,不幸的是没有。根据以下内容,gcc在编译时会生成额外的代码,这会影响程序中的分支数。有没有办法告诉gcc不要生成额外的代码,或者至少生成尽可能少的代码
根据上面提到的答案,使用
-O1
有助于生成更少的额外代码,但对我没有任何好处。相反,我覆盖了更多的行(这是错误的),覆盖了更少的一个分支。GCC的分支覆盖率统计数据取决于机器代码级别的分支,而不仅仅是源代码中明确的分支(if/else、switch/case、for、while、| |、&&&、?:,…)。编译器通常必须插入额外的分支才能实现语言功能,特别是在C++中:
- 静态初始化(C和C++)
- 析构函数
- 异常处理
- 安全检查,如绑定检查(通常不使用)
-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
更好,并且有很大的不同。做一个基准,看看他们带来的优势