gcov 和 switch 语句

Posted

技术标签:

【中文标题】gcov 和 switch 语句【英文标题】:gcov and switch statements 【发布时间】:2011-02-18 07:28:55 【问题描述】:

我正在使用 switch 语句在一些 C 代码上运行 gcov。我编写了测试用例来涵盖通过该 switch 语句的所有可能路径,但它仍然报告 switch 语句中的一个分支未采用,并且在“至少采用一次”统计信息中低于 100%。

这里有一些示例代码来演示:

#include "stdio.h"

void foo(int i)

    switch(i)
    
        case 1:printf("a\n");break;
        case 2:printf("b\n");break;
        case 3:printf("c\n");break;
        default: printf("other\n");
    


int main()

    int i;
    for(i=0;i<4;++i)
        foo(i);
    return 0;

我使用“gcc temp.c -fprofile-arcs -ftest-coverage”构建,运行“a”,然后运行“gcov -b -c temp.c”。输出指示交换机上有八个分支,其中一个(分支 6)未使用。

所有这些分支是什么?如何获得 100% 的覆盖率?

【问题讨论】:

.gcda 文件的内容有帮助吗? 【参考方案1】:

哦哦! bde 的程序集转储显示该版本的 GCC 正在将此 switch 语句编译为二叉树的某种近似,从集合的中间开始。所以它检查i是否等于2,然后检查它是大于还是小于2,然后对于每一边它分别检查它是等于1还是3,如果不是,则默认。

这意味着它有两种不同的代码路径可以得到默认结果——一种用于大于 2 的非 3 数字,另一种用于小于 2 但不是 1 的数字。

如果您将循环中的 i&lt;4 更改为 i&lt;=4,看起来您将获得 100% 的覆盖率,以便测试每一侧的路径。

(而且,是的,这很可能已经从 GCC 3.x 更改为 GCC 4.x。我不会说它是“固定的”,因为除了生成 gcov 结果之外,它并不是“错误的”令人困惑。只是在具有分支预测功能的现代处理器上,它可能很慢而且过于复杂。)

【讨论】:

【参考方案2】:

我使用 gcc/gcov 3.4.6 得到了相同的结果。

对于 switch 语句,它通常应该为每个 case 语句生成两个分支。一个是案例是否为真并且应该被执行,另一个是一个“fallthrough”分支,继续到下一个案例。

在您的情况下,gcc 似乎正在为最后一种情况创建一个“fallthrough”分支,这没有任何意义,因为没有什么可陷入的。

这是 gcc 生成的汇编代码的摘录(为了便于阅读,我更改了一些标签):

    cmpl    $2, -4(%ebp)
    je  CASE2
    cmpl    $2, -4(%ebp)
    jg  L7
    cmpl    $1, -4(%ebp)
    je  CASE1
    addl    $1, LPBX1+16
    adcl    $0, LPBX1+20
    jmp DEFAULT
L7:
    cmpl    $3, -4(%ebp)
    je  CASE3
    addl    $1, LPBX1+32
    adcl    $0, LPBX1+36
    jmp DEFAULT

我承认我对 x86 汇编不太了解,也不了解 L7 标签的使用,但它可能与额外的分支有关。也许对 gcc 有更多了解的人可以解释这里发生了什么。

听起来这可能是旧版本的 gcc/gcov 的问题,升级到新的 gcc/gcov 可能会解决问题,特别是考虑到结果看起来正确的另一篇文章。

【讨论】:

我怀疑 gcov 是一个失败的分支;它看起来更有可能是 gcc 做的。如果开启优化会怎样? default 的失败并没有错:毕竟下面可能有一个case 以避免执行特定于default 的代码。问题在于 switch 的最后一个语句有一个失败,因为没有什么可以陷入的。 @***s 开启优化并没有改变问题,而且看起来如果我使用 -O3 或更高版本会增加更多分支。 @Matthieu 我同意,这更有意义。我已经编辑了我的回复以反映这一点。 @bde:啊,好吧。这么多的想法!【参考方案3】:

你确定你正在运行 a.out 吗?这是我的结果(gcc 4.4.1):

File 't.c'
Lines executed:100.00% of 11
Branches executed:100.00% of 6
Taken at least once:100.00% of 6
Calls executed:100.00% of 5
t.c:creating 't.c.gcov'

【讨论】:

他说ran "a",对我来说这表明他运行a.exe并且正在使用Windows。 我想——默认情况下,我将 gcc 与 unix 相关联。结果看起来与意外运行不同版本的可执行文件一致。 是的,我在 Windows 上使用 MinGW,它是 gcc 3.4.5。这可能是最新版本的 gcc 中修复的问题吗?【参考方案4】:

我在 windows 上使用 mingw(这不是最新的 gcc),看起来这可能会在较新版本的 gcc 中解决。

【讨论】:

以上是关于gcov 和 switch 语句的主要内容,如果未能解决你的问题,请参考以下文章

switch case语句和if的区别

c++中for循环和switch语句哪个更高效

用if-else语句替换程序中switch语句

c语言的switch语句和java的switch语句有啥不同吗?

switch语句里不需要必须有break吗

流程控制switch语句和for语句