compiler/interpreter 在解释时创建函数通常是个好主意吗?

Is it generally a good idea for a compiler/interpreter to create functions while interpreting?

当我第一次学习 C++ 时,我注意到函数是从上到下创建的,这与 Java 等语言不同,后者的代码中函数 "declarations" 的顺序无关紧要。

C++ 示例:

#include <iostream>
using namespace std;

int main() {
    test();
    return 0;
}

void test() {

}

但是当你交换函数的顺序时,程序运行正常。

设计 C++ 时是故意的吗?

与用法相比,C 或 C++ 对函数定义的顺序没有太多要求。

C 允许函数在使用前声明,但(在 C89/90 中)实际上并不需要它。如果调用未声明的函数,则编译器需要对函数的类型做出某些假设(如果函数的定义不符合这些假设,则代码无效)。

然而,

C++ 确实要求自由函数在使用前至少要 声明1。函数定义还声明了该函数,因此微型程序通常在使用前先定义定义,以避免必须将声明与其定义分开编写。

对于 class 成员,C++ 稍微放宽了限制。例如,这是完全可以接受的:

class Foo { 
    void bar() { baz(); }
    void baz() {}
};

Java 主要区别在于简单地禁止所有自由函数,因此它只有成员函数,遵循与 C++ 成员函数大致相同的规则。


  1. 如果没有这个,基本上不可能支持某些 C++ 功能,例如函数重载。

问题源于一系列的约束:

  • 值语义要求编译 "call" 你需要知道参数和 return 类型大小。
  • 在编译同一个翻译单元期间,编译器必须可以使用该知识,但是...
  • 来自定义的知识仅在链接时可用,链接时是在编译之外发生的单独步骤。

更复杂的是,C++ 语法根据符号是变量还是类型来改变含义(因此,如果不了解这些知识,a<b>c 甚至不可能知道它的含义:包含三个变量的表达式或模板实例给定类型的变量)。

函数定义可以驻留在另一个源文件中,编译器在编译第一个源文件时无法访问它,因此无法知道 space 应该留在堆栈上的宽度对于参数和 return 传递。

您的示例 - 在一个广泛的项目中 - 将编码为

//test.h
double test();

__

//test.cpp
#include "test.h" //required to check decl & def consistence
double test()
{ /*...*/ }

__

//main.cpp
#include "test.h" // required to know about test() parameters and return
int main()
{ 
   double z = test();   //how does "=" translate? we need to know what test returns
}

这个"project"将使用独立的步骤编译:

g++ -c main.cpp //on a program developer machine
g++ -c test.cpp //on a library developer machine
g++ main.o test.o -o yourprogram //on a "package distributor" machine

None of these steps can collect a "global knowledge" about all "global symbols" and their "translation" at the same time. That's why we need headers to broadcast declarations to anyone have to use them

(请注意成员函数没有这个问题,它们都需要留在相同的 class 括号中,因此被授予适合相同的翻译单元)

像Java或python这样的语言没有这个问题,因为模块(不管如何编写和加载)都是由同一个语言机器实例加载的,即- 独一无二 - 可以收集所有符号和相关类型。

类似 D 的语言(在 "separate compilation" 的意义上类似于 C++)允许驻留在同一模块中的事物之间的顺序独立性,但对于来自其他模块的事物需要模块 "import",并且- 事实上 - 通过首先收集符号和类型然后进行调用翻译来进行两步翻译。

你可以看到这个问题的另一个描述here