【问题标题】:How to draw a Control Flow Graph from this code?如何从此代码中绘制控制流图?
【发布时间】:2018-11-27 13:11:59
【问题描述】:
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,但我不能做到这一点。我还需要确定基础路径和多个条件标准的测试。这不是作业问题,我只是试着理解课程材料。谢谢。

【问题讨论】:

  • 你确定这是 Java 而不是 C?
  • 哦,对不起,我添加了 Java,不是,是 C,但这无关紧要。

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


【解决方案1】:

这是来自 Wikipedia 的 CFG 的定义,我知道你已经知道了,但为了完整起见,我把它放在这里

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

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

下面是路径的定义

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

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

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

以下是我们绘制 CFG 时可以遵循的简单规则

  1. 任何语句都将是图中的一个节点
  2. 所有节点都有一条有向边,要么到达它们,要么离开它们,或者两者兼而有之。入口节点(第一条语句)只有出边,出口节点只有入边。
  3. 只有像if/else ifswitchloops 这样的条件语句才会有多个出边。
  4. 从节点出来的所有路径都会在某个点收敛,最坏的情况是它们会在出口处收敛。

这里有一个更好地解释它的备忘单

现在让我们将程序中的每个语句映射到我们将用来表示 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 之前充当了许多条件节点的连接节点。

致谢:我使用draw.io 创建上面发布的图像。

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

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

  1. 语句 1、2 和 3 是非条件语句,因此我创建了三个块将它们链接在一起。
  2. 语句 4 是一个条件语句。所以我必须为它创建 4 个块。第一个用于语句 4,第二个和第三个用于 TRUE、FALSE 边,最后一个用于 JOIN 节点。如果为真,则运行语句 5,否则运行语句 6。从语句 5 我们直接转到语句 16,这是我们的连接节点。最后,我们将块 4 链接到块 3 的出边。
  3. 现在语句 6 本身是一个条件语句,因此我们再次需要 4 个块。我们已经有一个自己的块 6。它的加入节点将是语句 16,就好像它的条件为真,然后运行语句 7,它直接转到 16。现在我们已经有了块 6 和 16,所以我们只需要块为 TRUE , FALSE 分支是语句 7 和 8。

等等,我们不断检查适用节点的备忘单并单独创建它们,然后与之前的节点链接。

【讨论】:

  • 很好的解释。仔细研究之后,这个图表中缺少一件事。条件句中的每个语句都必须有一个节点,它们不应被视为一个导致真或假的语句。例如,如果条件中的第一条语句为真,则程序转到另一个节点,这就是条件中的第二条语句(然后是第三条、第四条等)。这也会导致更大的复杂性。
  • 我不确定我是否理解,对于像if/else if 这样的条件节点,它只能有两条边,也只有两条边。您能否发布您提到的图表的示例或链接?控制流程图大多类似于流程图。
  • imgur.com/zEXaSsY。在这里,我为一个案例绘制了一个图表。这张图的复杂度是4,如果按照你说的那样画,就是2。
  • 哦,您的意思是,条件中的每个布尔表达式都将被视为一个单独的语句,是的,我可以看到这将如何提供有关短路流程的有趣信息。
  • 实际上复杂度为 5,因为您需要从 x = 100 向 y = 100 之后的边添加一条边。
【解决方案2】:

如果我们应该解释流程图,那么为什么要画它?图表必须如此清晰。

有很多在线工具,您可以输入代码,并为您提供类似图表。 你可以查看this

【讨论】:

  • 这不是CFG,而是控制流程图。它们是不同的。
  • CFG 只有基本块,但是这个图包含语句。
  • 看起来像是为您的服务做广告-1
【解决方案3】:

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

【讨论】:

  • 请注意,成绩尚未正确初始化。总有一天我会解决的。
【解决方案4】:
public static void main(String[] args) {
    double n1, n2, n3;
    Scanner in = new Scanner(System.in);
    System.out.print("Enter three numbers: ");
    n1 = in.nextDouble();
    n2 = in.nextDouble();
    n3 = in.nextDouble();
    if (n1 <= n2 && n1 <= n3)
        System.out.print(n1 + " is the smallest number.");
    else if (n2 <= n1 && n2 <= n3)
        System.out.print(n2 + " is the smallest number.");
    else
    System.out.print(n3 + " is the smallest number.");    
}

【讨论】:

  • 虽然此代码 sn-p 可能会解决问题,但including an explanation 将帮助人们了解您的代码建议的原因。
  • 此代码与所提出的问题完全无关
猜你喜欢
  • 1970-01-01
  • 2012-10-18
  • 2022-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多