12

我正在使用 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% 的覆盖率?

4

4 回答 4

5

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

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

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

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

于 2010-05-13T05:28:00.473 回答
3

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

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

在您的情况下,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 可能会解决问题,特别是考虑到结果看起来正确的另一篇文章。

于 2010-05-11T19:41:12.997 回答
1

你确定你正在运行 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'
于 2010-05-11T19:34:30.057 回答
0

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

于 2010-10-08T14:32:06.060 回答