1

原话是

进程和过程之间的区别可能令人困惑的一个原因是,大多数公共语言(包括 Ada、Pascal 和 C)的实现都设计为这样一种方式,即任何递归过程的解释都会消耗大量内存,而内存量会随着过程调用的数量,即使所描述的过程原则上是迭代的。因此,这些语言只能通过使用特殊用途的“循环结构”来描述迭代过程,例如 do、repeat、until、for 和 while。

我不熟悉C语言,Java或C#呢?他们也是这样吗?为什么?

注意:我以为作者在谈论不同语言的能力。但实际上它只是编译器的不同实现。

4

4 回答 4

3

C(和类似语言)通常使用调用堆栈来存储每个函数的本地变量。每次调用函数时,都会占用更多的堆栈;每次函数返回时,堆栈使用量都会减少。

但是,智能编译器没有理由不能在适当的情况下进行尾调用优化等事情,从而消除堆栈的使用。在像 Lisp 这样的语言中,我认为解释器需要执行这样的优化,所以这可能是作者试图做出的区分。

于 2012-07-21T15:52:29.123 回答
2

他基本上是想说这些语言的编译器不能进行尾递归消除。长话短说,他错了(或者无论如何都过度概括了——我想“大多数实现”已经足够狡猾的措辞了,它在技术上可能是正确的,尽管充其量是误导)。虽然我当然不能保证所有其他语言的每个编译器都会消除尾递归,但毫无疑问,至少有一些 C 和 C++ 编译器(例如,英特尔 C++、gcc/g++)可以并且将会。我没有检查过,但考虑到 GNAT(Gnu Ada 编译器)使用相同的优化器以及它们的 C 和 C++ 编译器,我的直接猜测是它也可以进行尾递归消除。

自从我使用 Pascal 以来已经有足够长的时间了,我无法对它做出明智的评论——我的直接猜测是“不”,但这与语言本身几乎没有关系,主要归结为事实目前对 Pascal 的大多数使用都可以追溯到 Borland,而且他们似乎从未在优化代码生成方面投入太多精力。

于 2012-07-21T15:52:42.560 回答
1

你问:C#呢?

C# 与 Java 类似,但与大多数 C/C++ 或 ADA 实现不同,它编译为中间语言,然后进一步编译,通常在运行时由“即时编译器”进行编译。

在撰写本文时,C# 编译器不会执行尾递归消除,但 JIT 可以。

有关详细信息,请参阅http://blogs.msdn.com/b/clrcodegeneration/archive/2009/05/11/tail-call-improvements-in-net-framework-4.aspx

于 2012-07-21T17:12:19.217 回答
0

它与编译器的实现无关。

你错过了他试图提出的重点,即流程和程序之间的区别。一个过程可能是递归的,即使它正在实现的底层过程原则上是迭代的;和递归过程消耗堆栈。

于 2012-07-22T02:15:10.533 回答