gcov和switch语句
我用switch语句在一些C代码上运行gcov。 我已经编写了测试用例来覆盖通过switch语句的每条可能路径,但它仍然在switch语句中报告没有采用的分支,并且在“采取至少一次”状态下报告的分支不到100%。
这里有一些示例代码来演示:
#include "stdio.h"
void foo(int i)
{
switch(i)
{
case 1:printf("an");break;
case 2:printf("bn");break;
case 3:printf("cn");break;
default: printf("othern");
}
}
int main()
{
int i;
for(i=0;i<4;++i)
foo(i);
return 0;
}
我用“ gcc temp.c -fprofile-arcs -ftest-coverage
” gcc temp.c -fprofile-arcs -ftest-coverage
,运行“ a
”,然后执行“ gcov -b -c temp.c
”。 输出指示交换机上有八个分支,一个(分支6)未被占用。
什么是所有这些分支机构,我如何获得100%的覆盖率?
啊哈! bde的程序集转储显示该版本的GCC正在将此开关语句编译为二叉树的一些近似值,从该集的中间开始。 所以它检查i
是否等于2,然后检查它是大于还是小于2,然后对每一边检查它是否分别等于1或3,如果不相等,则它将进入默认值。
这意味着它有两种不同的代码路径可以获得默认结果 - 一个是高于2的数字不是3,另一个是低于2的数字不是1。
看起来,如果你改变,你会得到100%的覆盖率i<4
在循环到i<=4
,以便测试每边的路径。
(而且,是的,这很可能已经从GCC 3.x变为GCC 4.x.我不会说它是“固定的”,因为除了使gcov结果混淆外,它不是“错误的”。只是在具有分支预测的现代处理器上,它可能很慢并且过于复杂。)
我使用gcc / gcov 3.4.6获得了相同的结果。
对于switch语句,通常应该为每个case语句生成两个分支。 一个是如果案件是真实的并且应该被执行,另一个是“下落”分支继续下一个案件。
在你的情况下,看起来海湾合作委员会正在为最后一个案例制定一个“延期”分支,这是没有意义的,因为没有什么可以陷入。
下面是由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可能会解决问题,尤其是考虑到结果看起来正确的其他帖子。
你确定你正在运行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'
链接地址: http://www.djcxy.com/p/51003.html