我使用Frama-C工具生成该程序的依赖图(main.c)。
#include<stdio.h>
int main()
{
int n,i,m,j;
while(scanf("%d",&n)!=EOF)
{
m=n;
for(i=n-1;i>=1;i--)
{
m=m*i;
while(m%10==0)
{
m=m/10;
}
m=m%10000;
}
m=m%10;
printf("%5d -> %d\n",n,m);
}
return 0;
}
命令是:
frama-c -pdg -dot-pdg main main.c
dot -Tpdf main.main.dot -o main.pdf
结果是
我的问题是为什么语句“m = m * i;”,“m = m%10000”不映射到节点。结果似乎不正确,因为代码中有三个循环。
答案 0 :(得分:6)
C程序的切片器只有在定义目标时才能在实践中使用 保留已定义的执行,允许切片器更改未定义的执行。
否则,只要x = *p;
无法确定p
是该点的有效指针,切片器就无法删除x
等语句,即使它知道它确实存在不需要p
,只是因为如果删除了该语句,则scanf()
在该点为NULL的执行会发生变化。
Frama-C不处理复杂的库函数,例如n
。因此,它认为在没有初始化的情况下使用局部变量frama-c -val main.c
。
输入main.c:10:[kernel] warning: accessing uninitialized left-value:
assert \initialized(&n);
...
[value] Values for function main:
NON TERMINATING FUNCTION
你应该得到一个警告:
assert
单词-val
表示Frama-C的选项n
无法确定是否已定义所有执行,而“NON TERMINATING FUNCTION”表示无法找到单个已定义的执行程序继续。
未初始化变量的未定义使用是PDG删除大多数语句的原因。 PDG算法认为它可以删除它们,因为它们是在它认为是未定义的行为之后,第一次访问变量scanf()
。
我稍微修改了你的程序,用一个更简单的语句替换#define EOF (-1)
int unknown_int();
int scan_unknown_int(int *p)
{
*p = unknown_int();
return unknown_int();
}
int main()
{
int n,i,m,j;
while(scan_unknown_int(&n) != EOF)
{
m=n;
for(i=n-1;i>=1;i--)
{
m=m*i;
while(m%10==0)
{
m=m/10;
}
m=m%10000;
}
m=m%10;
printf("%5d -> %d\n",n,m);
}
return 0;
}
调用:
dot
我得到了以下的PDG。据我所知,它看起来很完整。如果您知道的布局程序比dot
更好,但接受while
格式,则很有可能使用它们。
请注意,最外面
tmp != -1
的条件变为tmp != -1
。图的节点是程序的内部标准化表示的语句。条件tmp = unknown_int();
对语句frama-c -print main.c
的节点具有数据依赖性。您可以使用 while (1) {
int tmp;
tmp = scan_unknown_int(& n);
if (! (tmp != -1)) { break; }
显示内部表示,它将显示最外面的循环条件已被分解为:
{{1}}
除其他外,这有助于切除仅删除可以删除的复杂语句的部分,而不必保留整个复杂语句。