我现在正在使用编译器类,我们正处于构建CFG以实现优化的程度。我无法弄清楚的一件事是一个程序有多少CFG?我见过的每个例子似乎都是简单代码段的CGF。所以,如果你有一个程序说三个功能。你是否为每个功能都有一个单独的CFG,或者整个程序有一个大的CFG?
答案 0 :(得分:3)
每个功能的CFG通过被叫方连接。如果一个函数调用另一个函数,例如:
0 void foo() { /* do stuff */ }
1 void bar() { /* do stuff */ }
2
3 void baz() {
4 foo(); // Callsite for foo. Control transfers to foo, then foo returns here.
5 bar(); // Callsite for bar. Control transfers to bar, then bar returns here.
6 }
然后baz
的控件图将包含一个转到foo
图表的边。同样地,因为foo
最终将返回baz
(以及可能从其中调用的任何其他地方),因此foo
图的末尾将返回到在foo
中致电baz
后的声明。在这里,下一个语句是第5行对bar
的调用。此时,bar
调用点到bar
的CFG有一条边,而bar
的出口点有一条线。 {1}}回到baz
的末尾。
基本上你需要考虑的是“接下来会执行什么代码”。这会告诉您控制图中边缘的位置。函数调用转移控制直到函数返回,这意味着从调用点到函数CFG的边缘再返回。
请注意,并非所有完整程序的CFG都是连接图。如果您正在分析的程序中有unreachable code,那么这将是它自己的完整CFG中未连接的部分。例如如果您在上面的示例中取消了对bar
的调用,那么bar
会将自己的图表放在一边,而baz
和foo
将通过边连接
答案 1 :(得分:1)
那么,你可以为每个函数构建一个CFG,然后 - 如果你想做什么,可以将它们组合成一个完整的函数。然而,整个程序CFG可能非常大,因此它们通常不能很好地作为示例。