Gcov和switch语句

12

我正在运行gcov对一些包含switch语句的C代码进行覆盖率测试。我编写了测试用例以覆盖该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"。输出结果显示 switch 中有八个分支,其中一个(第6个分支)未被执行。

所有这些分支都是什么意思,如何实现100%的覆盖率?


.gcda文件的内容有帮助吗? - Cascabel
4个回答

5
哦! bde 的汇编转储显示,该版本的 GCC 将此 switch 语句编译为某种二叉树的近似值,从集合的中间开始。因此,它首先检查 i 是否等于2,然后检查它是否大于或小于2,并且对于每个侧面,它都会检查它是否分别等于1或3,如果不是,则进入默认值。
这意味着有两个不同的代码路径可以到达默认结果——一个用于大于2但不是3的数字,另一个用于小于2但不是1的数字。
看起来,如果您将循环中的 i<4 更改为 i<=4,以便测试每个侧面的路径,则可以获得100%的覆盖率。
(是的,这很可能是从 GCC 3.x 到 GCC 4.x 改变的内容。我不会说它已经“修复”,因为它并不完全“错误”,除了使 gcov 结果混乱之外。只是在具有分支预测功能的现代处理器上,它可能既慢又过于复杂。)

3

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

对于switch语句,它通常应该为每个case语句生成两个分支。一个是如果case为真,则执行该分支,另一个是“fallthrough”分支,继续执行下一个case。

在你的情况下,看起来gcc正在为最后一个case生成一个“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在做这件事。如果您打开优化,会发生什么? - Brooks Moses
default中使用fallthrough并没有什么问题:毕竟,下面可能有一个case来避免执行特定于default的代码。问题在于,在switch的最后一个语句中使用fallthrough,因为没有任何可以落入其中的内容。 - Matthieu M.
@Brooks 打开优化并不改变问题,而且看起来如果我使用 -O3 或更高版本,它会添加更多的分支。 - WildCrustacean
@Matthieu 我同意,那样更有意义。我已经编辑了我的回复以反映这一点。 - WildCrustacean
@bde:啊,好吧。那个想法就这样了! - Brooks Moses
显示剩余2条评论

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'

他说“ran "a"”,这让我认为他运行了a.exe并且正在使用Windows。 - nategoose
我想默认情况下我会将gcc与Unix关联起来。结果看起来像是意外运行了不同版本的可执行文件。 - ergosys
是的,我在Windows上使用MinGW,它是gcc 3.4.5。这可能是在更近期的gcc版本中修复的问题吗? - Matt

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接