Howdoesthecompilerdifferentiateindentically-nameditems
In the following example:
int main(void) {
int a=7;
{
int a=8;
}
}
The generated assembly would be something like this (from Compiler Explorer) without optimizations:
main:
pushq %rbp
movq %rsp, %rbp
movl $7, -4(%rbp) // outer scope: int a=7
movl $8, -8(%rbp) // inner scope: int a=8
movl $0, %eax
popq %rbp
ret
How does the compiler know where the variable is if there are duplicately-named variables? That is, when in the inner scope, the memory address is at %rbp-8 and when in the outer scope the address is at %rbp-4.
回答
有很多方法可以实现局部作用域规则。这是一个简单的例子:
- 编译器可以保留一个嵌套范围列表,每个范围都有自己的符号定义列表。
- 这个列表最初只有一个全局范围的元素,
- 当它解析一个函数定义时,它会在函数参数名称的范围列表前面添加一个新的范围元素,并将每个参数名称与该范围元素的标识符列表中的相应信息添加在一起。
- 对于每个新块,它会在作用域列表前面添加一个新的作用域元素。
for (在第一个子句中也为定义引入了一个新的范围。 - 在离开作用域时(在块的末尾),它从作用域列表中弹出作用域元素。
- 在解析声明或定义时,如果对应的符号已经在当前作用域的列表中,则是局部重定义,这是禁止的(
extern前向声明除外)。否则,该符号将添加到范围列表中。 - 当它遇到表达式中的符号时,它会在当前作用域的符号列表中查找它,并在作用域列表中的每个后续作用域中查找它,直到找到它为止。如果找不到符号,则它是未定义的,根据最新的 C 标准,这是错误的。否则,符号信息将用于进一步解析和代码生成。
上述步骤的类型和对象名称进行的,符号的一个单独的列表被维持struct,union和enum标记。
在所有这些发生之前,在程序翻译的单独阶段执行预处理。
THE END
二维码