复习软件测试,恰巧遇到程序切片的问题;
学习之余做下笔记,如有错误恳请指正。
什么是程序切片技术
思想
对程序进行裁剪,使得所得到的程序代码仍能反映原程序的部分特征程序切片专门针对这类问题,它按切片准则来裁剪程序,使人们能把注意力集中在相关的程序代码上
定义
一个程序切片是由程序中的一些语句和判定表达式组成的集合,给定一个程序P和P中的一个变量集合V,变量集合V在语句n上的一个片,记作S(V,n),是P中对V中的变量值作出贡献的所有语句集合。
贡献:控制依赖、数据依赖
如果不管是否包含语句片段,V中各变量的值都保持不变,那么排除该语句片段
简而言之,程序切片是根据某个被选定的程序节点以及其控制依赖、数据依赖得到的。
以如下代码段为例
cin>>k;
int t = 0;
int f = 1;
while (k > 0){
t = t+k;
f = f*k;
k = k-1;
cout<<t<<endl;
cout<<f<<endl;}
为了方便按照行号说明结点,码风奇怪了些
绘制控制依赖图
假设C是包含结点n1和n2的控制流图,n1是一个判断结点,如果下面两个条件同时成立,则称结点n2控制依赖于n1:
1. 至少存在一条从n1到程序出口的路径,该路径包含n2;
2. 至少存在一条从n1到程序出口的路径,该路径不包含n2;
依据上面给出的代码,绘制出控制流图
如图,判定结点为④;
从判定结点④开始到出口共有两条路径,分别是:
- ④⑤⑥⑦⑧⑨④⑩
- ④⑩
根据上面给出的控制依赖定义可以得知:
⑤⑥⑦⑧⑨控制依赖于④
由此,可以画出控制依赖图:
绘制数据依赖图
假设D是包含结点n1和n2的数据依赖图,如果下面两个条件同时成立,则称结点n2数据依赖于n1:
1. 变量v在n1处**定义**、在n2处**引用**
2. 存在一条从n1到n2的**非空**路径,不包含任何**重定义**v的结点
这里解释一下“定义”和“引用” 如上例代码中,②是对k的定义,⑤是对k的引用,同时也是对k的重定义
如此,我们可以得到依赖关系如下:
- 对于k:
④依赖于①,⑦依赖于①,④依赖于⑦,⑦依赖于⑦,⑤依赖于⑦,⑥依赖于⑦;
注:
1.while循环中,⑦对⑦循环重定义
2.⑤不依赖于①,也是因为在循环中⑦会对⑤进行重定义,不满足定义要求的第二条
- 对于t:
⑧依赖于⑤,⑤依赖于②;
- 对于f:
⑥依赖于③,⑥依赖于⑨;
由此我们可以画出数据依赖图
至此,我们完成了数据依赖图和控制依赖图的绘制。
通过程序依赖图得到静态切片
将上面画出的数据依赖图和控制依赖图叠加,即可得到程序依赖图。
在程序依赖图中求出所关心结点的逆向传递闭包就可以得出它所数据依赖、控制依赖的结点。
下面给出一个定义:
假设我们给定感兴趣的程序点p和变量集合V来作为切片标准(<p, V>),那么所有影响该程序点p处的变量V的程序语句(statement)构成切片。
例如对于切片准则<8,t>,下图中高亮节点即为结点⑧的传递闭包
由此可以得到例程关于切片准则<8,t>的静态切片
cin>>k;
int t = 0;
while (k > 0){
t = t+k;
k = k-1;
cout<<t<<endl;
}
参考:
https://zhuanlan.zhihu.com/p/379422670