我正在使用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%的覆盖率?
答案 0 :(得分:4)
大穗! bde的程序集转储显示该版本的GCC正在将此switch语句编译为二进制树的一些近似值,从集合的中间开始。因此它检查i
是否等于2,然后检查它是否大于或小于2,然后对于每一方它检查它是否分别等于1或3,如果不是,则它将变为默认值。
这意味着它有两个不同的代码路径可以获得默认结果 - 一个用于高于2且不是3的数字,一个用于低于2的数字而不是1。
如果您将循环中的i<4
更改为i<=4
,看起来您将获得100%的覆盖率,以便测试每一方的路径。
(而且,是的,这很可能已经从GCC 3.x变为GCC 4.x.我不会说它是“固定的”,因为除了制作gcov结果之外它不是“错误的”在具有分支预测的现代处理器上,它可能很慢而且过于复杂。)
答案 1 :(得分:2)
我使用gcc / gcov 3.4.6获得相同的结果。
对于switch语句,它通常应为每个case语句生成两个分支。一种情况是,如果情况属实并且应该执行,另一种情况是“渐进式”分支继续下一个案例。
在你的情况下,看起来gcc正在为最后一个案例制作一个“通过”分支,这没有任何意义,因为没有任何东西可以落入。
以下是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可能会解决问题,特别是考虑到结果看起来正确的其他帖子。
答案 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'
答案 3 :(得分:0)
我在windows上使用mingw(这不是最新的gcc),看起来这可能会在较新版本的gcc中进行整理。