程序的汇编和执行 - 两次通过汇编器

Assembly and Execution of Programs - Two pass assembler

在阅读一本关于机器指令和程序的书时,我遇到了一个特别的观点,它说汇编程序会扫描整个源程序两次。它在第一次 pass/scan 期间构建一个符号 table 并在第二次扫描期间将整个程序与其相关联。汇编程序需要以类似的方式为函数提供地址。
现在,既然汇编器对程序进行了两次遍历,为什么还需要先声明一个函数才能使用呢?汇编程序不会在第一次通过时为函数提供地址,然后在第二次通过时将其与程序相关联吗? 我正在考虑在这种情况下进行 C 编程。

简单的回答是,C 程序要求在使用函数之前声明函数,因为 C 语言被设计为由编译器一次性处理。它与汇编程序和函数地址无关。编译器在使用之前需要知道符号的类型,无论是函数、变量还是其他。

考虑这个简单的例子:

int foo() { return bar(); }
int (*bar)();

为了生成正确的代码,编译器需要知道 bar 不是函数,而是指向函数的指针。仅当您将 extern int (*bar)(); 放在 foo 的定义之前时,该代码才有效,因此编译器知道 bar 是什么类型。

虽然该语言在理论上可以设计为要求编译器使用两次传递,但这需要对语言的设计进行一些重大更改。要求两次通过还会增加编译器所需的复杂性,从而减少可以托管 C 编译器的平台数量。在最初开发 C 的那一天,这是非常重要的考虑因素,当时 64K(65,536)字节的 RAM 是很多内存。即使在今天也会对大型程序的编译时间产生显着影响。

请注意,C 语言确实通过支持隐式函数声明来允许您想要的东西。 (在我上面的示例中,当 bar 之前未声明时,foo 中会发生什么。)但是此功能已过时、受限且被认为是危险的。