【问题标题】:Code Coverage (Lcov) incorrectly showing 100% coverage代码覆盖率 (Lcov) 错误地显示 100% 覆盖率
【发布时间】:2020-07-12 10:37:25
【问题描述】:

我有以下设置(使用g++ 10 和lcov 1.14):

g++ SampleScript.cpp -g -O0 -fprofile-arcs -ftest-coverage -o MyScript
./MyScript

lcov -d . -c -o coverage.info --rc lcov_branch_coverage=1
genhtml coverage.info -o cov_out --legend --branch-coverage

/* SampleScript.cpp */

class Container
{
public:
    Container()
        : m_value(0) { }

    Container(int value)
        : m_value(value) { }

    int& value()
    {
        return m_value;
    }

    const int& value() const
    {
        return m_value;
    }

private:
    int m_value;
};

int main()
{
    const Container c;
    return c.value();
}

但即使我的代码跳过了 2 个函数(1 个构造函数和 1 个 value() 函数),结果输出也错误地显示了 100% 的覆盖率。 我是否缺少任何设置?

【问题讨论】:

    标签: c++ code-coverage lcov


    【解决方案1】:

    因为函数是inline。在类/结构定义中定义成员函数时,它是隐式内联函数。编译器仅在调用内联函数时为其生成代码。而 lcov 使用 GCC 内置的 gcov 覆盖机制,该机制基于在生成的机器代码中插入计数器。所以:

    • 编译器不会为这些函数生成代码
    • 因此 gcov 不知道这些函数存在
    • 因此 lcov 不知道这些函数存在

    这是所有 gcov/lcov/gcovr 样式覆盖工具的系统限制。

    如果您想确保这些工具能够识别函数何时被发现,请确保它不是内联的(并且具有外部链接),或者确保您的测试包含对该函数的调用(即使调用从未执行)。或者使用不同的覆盖工具来解析源代码。

    C++ 中的inline 概念不是指内联优化,而是更多地与链接和单一定义规则(ODR)相关。函数/对象的定义必须在使用它们的所有编译单元中可见,并且链接器可以合并其他冲突的定义(ODR 的例外)。另一方面,如果不使用内联函数,编译器通常不会发出代码。当使用 inline 关键字标记或在类/结构体中定义时,函数可以是内联的:

    struct Example {
      void inline_function() { ... }
      void also_inline();
      void not_inline();
    };
    
    inline void Example::also_inline() { ... }
    
    void Example::not_inline() { ... }
    

    【讨论】:

    • 谢谢。我将如何 (a) 确保函数没有被内联,或 (b) 确保我的测试包含“即使调用从未执行过也对该函数的调用”?
    • @Phil-ZXX 我编辑了答案,简要讨论了 C++ 的“内联”概念。 (a) 你可以在类中声明函数签名,并在外部定义int& Container::value() { ... }。 (b) 对不起,我可能把它弄得比必要的复杂了。如果您在某处调用该函数,则会生成该函数的代码。当然,你也可以只为它写一个测试用例,所以这个建议在实践中并没有多大帮助……
    猜你喜欢
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 2015-10-06
    • 2017-05-31
    • 2012-01-18
    • 2016-10-07
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多