0

如果您尝试使用尚未(肯定)分配/初始化的局部变量,Java 或 C# 等语言的编译器会抱怨。

我想知道该功能是如何在编译器中实现的。显然,关于变量初始化状态的信息可以保存为布尔标志,并在检测到赋值语句后进行相应设置。但是像循环体或条件语句这样的(嵌套的)子范围呢?

4

2 回答 2

2

这可以通过计算活跃度信息来实现。

编译器通常将源代码转换为较低级别的中间表示 (IR),将该代码划分为基本块(无跳转代码),然后从那里构建控制流图 (CFG)。

活性分析可以计算每个基本块的 LiveOut 集。如果变量在某个基本块的 LiveOut 集中,则意味着该变量将在后续块中使用,而不会被杀死(分配给)。

CFG 有两个特殊节点:一个 ENTRY 节点和一个 EXIT 节点。如果变量在 ENTRY 节点的 LiveOut 集中,这意味着该变量将在没有赋值之前被使用。

指针会使这种分析复杂化。例如,考虑以下代码

 int *p, x, y;
 ...
 *p = 123;
 y = x*2;

为了不报告误报,编译器必须执行所谓的指针分析。该分析所做的是为每个指针计算指针可能(或必须)指向的可能目标集。在上面的例子中,如果编译器发现 p 指向 x,那么 x 在下一行中使用时不会被初始化。

于 2015-06-25T14:55:52.517 回答
0

这相对容易。在使用变量之前,每个可能的代码执行路径都必须导致赋值。循环也被视为可能的路径;对于这种分析,重复无关紧要。

于 2015-06-24T18:58:24.070 回答