代码覆盖中的块的技术术语是基本块。直接从the Wikipedia entry婴儿床:
基本块中的代码有一个
入口点,意味着其中没有代码
是跳转的目的地
程序中任何地方的指令,
它有一个出口点,意思是
只有最后一条指令可以导致
开始执行代码的程序
不同的基本块。在这些之下
情况下,每当第一个
基本块中的指令是
执行,其余指令
必须只执行一次,
按顺序排列。
基本块在代码覆盖中很重要,因为我们可以在基本块的开头插入一个探针。当这个探针被命中时,我们知道该基本块中的所有以下指令都将被执行(由于基本块的属性)。
不幸的是,对于编译器(尤其是优化),源代码如何映射到基本块并不总是很明显。最简单的判断方法是查看生成的程序集。比如看你原来的main&testfunction:
对于main,我看到下面的程序集(与原始源交错)。与Peter does here 类似,我已经注意到基本块的开始位置。
int main()
{
013B2D20 push ebp <--- Block 0 (initial)
013B2D21 mov ebp,esp
013B2D23 sub esp,40h
013B2D26 push ebx
013B2D27 push esi
013B2D28 push edi
testfunction(-1);
013B2D29 push 0FFFFFFFFh
013B2D2B call testfunction (013B10CDh)
013B2D30 add esp,4 <--- Block 1 (due to call)
testfunction(1);
013B2D33 push 1
013B2D35 call testfunction (013B10CDh)
013B2D3A add esp,4 <--- Block 2 (due to call)
}
013B2D3D xor eax,eax
013B2D3F pop edi
013B2D40 pop esi
013B2D41 pop ebx
013B2D42 mov esp,ebp
013B2D44 pop ebp
013B2D45 ret
我们看到main 有三个基本块:一个是初始块,另外两个是因为函数调用。查看代码,这似乎是合理的。 testfunction 有点强硬。单看源码,貌似有三个块:
- 功能与逻辑测试入口(
input > 0)
- 条件为真分支 (
return 1)
- 条件假分支 (
return 0)
但是,由于实际生成的程序集,有四个块。我假设您在禁用优化的情况下构建了代码。当我在调试配置(禁用优化)中使用 VS2010 构建时,我看到 testfunction 的以下反汇编:
int testfunction(int input)
{
013B2CF0 push ebp <--- Block 0 (initial)
013B2CF1 mov ebp,esp
013B2CF3 sub esp,40h
013B2CF6 push ebx
013B2CF7 push esi
013B2CF8 push edi
if (input > 0) {
013B2CF9 cmp dword ptr [input],0
013B2CFD jle testfunction+18h (013B2D08h)
return 1;
013B2CFF mov eax,1 <--- Block 1 (due to jle branch)
013B2D04 jmp testfunction+1Ah (013B2D0Ah)
}
else {
013B2D06 jmp testfunction+1Ah (013B2D0Ah) <--- Not a block (unreachable code)
return 0;
013B2D08 xor eax,eax <--- Block 2 (due to jmp branch @ 013B2D04)
}
}
013B2D0A pop edi <--- Block 3 (due to being jump target from 013B2D04)
013B2D0B pop esi
013B2D0C pop ebx
013B2D0D mov esp,ebp
013B2D0F pop ebp
013B2D10 ret
这里,我们有四个块:
- 函数入口
- 条件为真分支
- 条件假分支
- 共享的function epilog(清理堆栈并返回)
如果编译器在条件真和条件假分支中都复制了函数 Epilog,您将只能看到三个块。此外,有趣的是,编译器在013B2D06 处插入了一条虚假的jmp 指令。因为它是不可访问的代码,所以它不被视为基本块。
一般来说,所有这些分析都是多余的,因为整体代码覆盖率指标会告诉您需要了解的内容。这个答案只是为了强调为什么块的数量并不总是很明显或者是预期的。