如何从此代码中绘制控制流图?

时间:2018-06-18 16:20:46

标签: c unit-testing testing control-flow-graph

int main() {
    int i, grade = 0;
    printf (" Enter points: \n");
    scanf ("%d", &i);
    if (i >= 50 && i <= 60) grade = 5;
    else if (i > 50 && i <= 60) grade = 6;
    else if (i > 60 && i <= 70) grade = 7;
    else if (i > 70 && i <= 80) grade = 8;
    else if (i > 80 && i <= 90) grade = 9;
    else if (i > 90 && i <= 100) grade = 10;
    char sign = ' ';
    if (grade) {
        int p = i % 10;
        if (grade != 5) {
            if (p >= 1 && p <= 3)
                sign = '-';
            else if (grade != 10 && (p >= 8 || p == 0))
                sign = '+';
        }
        printf (" The grade is %d%c. \n", grade, sign);

    }
    return 0;
}

如何从此代码中绘制控制流图?如果有人能展示这个过程,我将不胜感激。我能够从一个非常简单的案例中得出CFG,但我不能这样做。此外,我需要确定多条件标准的基本路径和测试。这不是一个家庭作业问题,我只是试着理解课程材料。感谢。

3 个答案:

答案 0 :(得分:4)

如果我们要解释流程图,那么为什么要绘制流程图?该图必须非常清晰。

control flow diagram

有很多在线工具,您可以键入代码,这些工具将为您提供类似图表的信息。 您可以检查this

答案 1 :(得分:4)

这是Wikipedia中CFG的定义,我知道您已经知道这一点,但是出于完整性考虑,我将其放在此处

  

计算机科学中的控制流图(CFG)是一种表示,   使用图形符号表示可能会通过的所有路径   程序执行期间。

参考:https://en.wikipedia.org/wiki/Control_flow_graph

以下是路径的定义

  

路径:CFG(静态)上的节点序列,包括入口节点   和出口节点;路径段:沿路径的节点的子序列

参考:http://web.cs.iastate.edu/~weile/cs513x/4.ControlFlowAnalysis.pdf

所以绘制一个图的原因是确定程序所采用的所有可能路径,这可能有助于我们在不实际运行程序的情况下确定测试覆盖率之类的东西(静态分析)。

以下是绘制CFG的简单规则

  1. 任何语句都将成为图中的节点
  2. 所有节点都有一个有向边,要么到达要么走出它们,或者两者都有。入口节点(第一条语句)仅具有输出边缘,出口节点仅具有输入边缘。
  3. 只有条件语句,例如if/else ifswitchloops会具有多个输出边缘。
  4. 从节点出来的所有路径都将在某个时刻收敛,在最坏的情况下,它们会在Exit处收敛。

这是一个备忘单,可以更好地解释

CFG cheat sheet

现在,我们可以将程序中的每个语句映射到一个用于表示CFG节点的数字

   int main() {
1.     int i, grade = 0;
2.     printf (" Enter points: \n");
3.     scanf ("%d", &i);
4.     if (i >= 50 && i <= 60)
5.         grade = 5;
6.     else if (i > 50 && i <= 60)
7.         grade = 6;
8.     else if (i > 60 && i <= 70)
9.         grade = 7;
10.    else if (i > 70 && i <= 80)
11.         grade = 8;
12.    else if (i > 80 && i <= 90)
13.         grade = 9;
14.    else if (i > 90 && i <= 100)
15.         grade = 10;
16.    char sign = ' ';
17.    if (grade) {
18.        int p = i % 10;
19.        if (grade != 5) {
20.            if (p >= 1 && p <= 3)
21.                sign = '-';
22.            else if (grade != 10 && (p >= 8 || p == 0))
23.                sign = '+';
           }
24.        printf (" The grade is %d%c. \n", grade, sign);
       }
25.    return 0;
  }

这是按照上面备忘单图表中的说明创建的输出。请注意,之前节点16和24充当了许多条件节点的加入节点。

enter image description here

信用:我已经使用draw.io来创建上面发布的图像。

注意:绘制CFG的秘诀在于将每条语句独立于程序对待,绘制它,然后将其入口和出口链接到图的其余部分。

以下是我遵循的一些初始步骤

  1. 语句1、2和3是无条件的,因此我创建了三个将它们链接在一起的块。 step1
  2. 语句4是一个条件语句。因此,我必须为其创建4个块。首先是语句4,第二和第三条是TRUE,FALSE边,最后一个是JOIN节点。如果为true,则运行语句5;否则,运行语句6。从语句5直接转到语句16,这是我们的连接节点。最终,我们将块4链接到块3的输出边缘。 enter image description here
  3. 现在语句5本身是一个条件语句,因此我们再次需要4个块。我们本身已经有一个块5。为此,它的连接节点将是语句16,就好像它的条件为true一样,然后运行语句6并将其直接转到16。现在我们已经有了块6和16,所以我们只需要块为TRUE ,即语句7和8的FALSE分支。 step3

以此类推,我们一直在检查备忘单中是否有适用的节点,并单独创建它们,然后再链接至先前的节点。

答案 2 :(得分:1)

我的c前端工具Crokus(在githubrubygems上都提供)直接通过解析C代码来实现。

enter image description here