2010-05-11 96 views
12

我正在用switch语句在一些C代码上运行gcov。我已经编写了测试用例来覆盖通过switch语句的每条可能路径,但它仍然在switch语句中报告没有采用的分支,并且在“采取至少一次”状态下报告的分支不到100%。gcov和switch语句

下面是一些示例代码来演示:

#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%的覆盖率?

+0

.gcda文件的内容是否有帮助? – Cascabel 2010-05-11 19:52:35

回答

0

我在windows上使用mingw(这不是最新的gcc),它看起来像这样整理出更新版本的gcc。

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' 
+0

他说'跑'一个'',这对我来说建议他跑'a.exe'并使用windows。 – nategoose 2010-05-11 19:40:16

+0

我想 - 默认情况下,我把gcc和unix联系起来。结果看起来与偶然运行不同版本的可执行文件一致。 – ergosys 2010-05-11 20:01:48

+0

是的,我在Windows上使用MinGW,这是gcc 3.4.5。这可能是在更新版本的gcc中修复的吗? – Matt 2010-05-12 14:58:00

2

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

对于switch语句,通常应该为每个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可能会解决问题,尤其是考虑到结果看起来正确的其他帖子。

+0

我怀疑这是gcov做一个贯穿分支;它看起来更可能是gcc这样做。如果你打开优化会发生什么? – 2010-05-12 04:23:14

+0

为了避免执行特定于'default'的代码,在'default'后面可能有一个'case'是没有问题的。由于没有任何东西可以进入,所以最后一个转换语句的转换有什么不妥。 – 2010-05-12 12:24:33

+0

@Brooks打开优化不会改变问题,看起来好像我使用-O3或更高版本,它会添加更多的分支。 – WildCrustacean 2010-05-12 13:43:29

4

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

这意味着有两个不同的代码路径它到达默认结果 - 一个用于不属于3个数字大于2,和一个为不是1.

数低于2

如果您将循环中的i<4更改为i<=4,以便测试每边的路径,看起来您会达到100%的覆盖率。

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