gcov 和 switch 语句
我正在使用 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
”。输出指示交换机上有 8 个分支,其中一个(分支 6)未采用。
这些分支是什么以及如何获得 100% 的覆盖率?
I'm running gcov over some C code with a switch statement. I've written test cases to cover every possible path through that switch statement, but it still reports a branch in the switch statement as not taken and less than 100% on the "Taken at least once" stat.
Here's some sample code to demonstrate:
#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;
}
I built with "gcc temp.c -fprofile-arcs -ftest-coverage
", ran "a
", then did "gcov -b -c temp.c
". The output indicates eight branches on the switch and one (branch 6) not taken.
What are all those branches and how do I get 100% coverage?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(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 结果令人困惑之外,它并不是“错误的”。只是在具有分支预测的现代处理器上,它可能很慢而且过于复杂。)
Oho! bde's assembly dump shows that that version of GCC is compiling this switch statement as some approximation of a binary tree, starting at the middle of the set. So it checks if
i
is equal to 2, then checks if it's greater or less than 2, and then for each side it checks if it's equal to 1 or 3 respectively, and if not, then it goes to default.That means there are two different code paths for it to get to the default result -- one for numbers higher than 2 that aren't 3, and one for numbers lower than 2 that aren't 1.
Looks like you'll get to 100% coverage if you change that
i<4
in your loop toi<=4
, so as to test the path on each side.(And, yes, that's something that's very likely to have changed from GCC 3.x to GCC 4.x. I wouldn't say it's "fixed", as it's not "wrong" exactly aside from making the gcov results confusing. It's just that on a modern processor with branch prediction, it's probably slow as well as overly complicated.)
我使用 gcc/gcov 3.4.6 得到相同的结果。
对于 switch 语句,它通常应该为每个 case 语句生成两个分支。一个是情况是否为真并且应该执行,另一个是继续到下一个情况的“失败”分支。
在你的情况下,看起来 gcc 正在为最后一种情况创建一个“fallthrough”分支,这是没有意义的,因为没有什么可陷入的。
以下是 gcc 生成的汇编代码的摘录(为了可读性,我更改了一些标签):
我承认我对 x86 汇编了解不多,而且我不明白 L7 标签的使用,但它可能有与额外的分支有关。也许对 gcc 有更多了解的人可以解释这里发生了什么。
听起来这可能是旧版本的 gcc/gcov 的问题,升级到较新的 gcc/gcov 可能会解决该问题,特别是考虑到其他帖子的结果看起来正确。
I get the same result using gcc/gcov 3.4.6.
For a switch statement, it should normally generate two branches for each case statement. One is if the case is true and should be executed, and the other is a "fallthrough" branch that goes on to the next case.
In your situation, it looks like gcc is making a "fallthrough" branch for the last case, which doesn't make sense since there is nothing to fall into.
Here's an excerpt from the assembly code generated by gcc (I changed some of the labels for readability):
I admit that I don't know much about x86 assembly, and I don't understand the use of the L7 label but it might have something to do with the extra branch. Maybe someone with more knowledge about gcc can explain what is going on here.
It sounds like it might be an issue with the older version of gcc/gcov, upgrading to a newer gcc/gcov might fix the problem, especially given the other post where the results look correct.
你确定你正在运行 a.out 吗?这是我的结果(gcc 4.4.1):
Are you sure you are running a.out? Here is my results (gcc 4.4.1):
我在 Windows 上使用 mingw(这不是最新的 gcc),看起来这可能会在较新版本的 gcc 中得到解决。
I'm using mingw on windows (which is not the latest gcc) and it looks like this may be sorted out in newer versions of gcc.