c - 编译器如何区分同名项目
问题描述
在以下示例中:
int main(void) {
int a=7;
{
int a=8;
}
}
生成的程序集将是这样的(来自 Compiler Explorer),没有优化:
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
如果有重复命名的变量,编译器如何知道变量在哪里?也就是说,当在内部范围内时,内存地址在%rbp-8
,而在外部范围内时,地址在%rbp-4
。
解决方案
有很多方法可以实现本地范围规则。这是一个简单的例子:
- 编译器可以保留一个嵌套范围列表,每个范围都有自己的符号定义列表。
- 这个列表最初有一个全局范围的元素,
- 在解析函数定义时,它会在函数参数名称的作用域列表前面添加一个新的作用域元素,并将每个参数名称与该作用域元素的标识符列表中的相应信息一起添加。
- 对于每个新块,它会在范围列表前面添加一个新的范围元素。
for (
在它的第一个子句中也为定义引入了一个新的范围。 - 离开作用域时(在块的末尾),它会从作用域列表中弹出作用域元素。
- 在解析声明或定义时,如果对应的符号已经在当前作用域的列表中,则为局部重定义,这是禁止的(
extern
前向声明除外)。否则,该符号将添加到范围列表中。 - 当它在表达式中遇到一个符号时,它会在当前作用域的符号列表中查找它,并在作用域列表中的每个后续作用域中查找它,直到找到它。如果找不到符号,则它是未定义的,根据最新的 C 标准,这是一个错误。否则,符号信息将用于进一步的解析和代码生成。
对类型和对象名称执行上述步骤,为 和标签维护单独的struct
符号union
列表enum
。
在所有这些发生之前,在程序翻译的一个单独阶段中执行预处理。
推荐阅读
- mysql - MYSQL - 过滤连续的非空日期
- tensorflow - 如何在tensorflow中对所有全局和局部变量进行常量初始化?
- c# - 用于绑定到 WebBrowser 的附加属性不起作用
- php - 在不更改环境变量的情况下使用不同版本的 PHP 运行 composer
- python - 打印来自 2 个不同列表的数据及其索引
- javascript - 重试nodejs http.request(发布,放置,删除)
- apache-spark - 如何在独立和客户端模式下终止作业?
- typescript - 可选值最佳实践的 Redux/typescript 选择器?
- javascript - 在触发 Dialogflow 的 Fulfillment 的多个意图之间传递参数
- android - 设计编辑器不会自动看到属性更改