C尾调用优化

dsi*_*cha 32 c standards tail-recursion tail-call-optimization

我经常听到人们说C不执行尾部呼叫消除.虽然标准不能保证,但是无论如何,它是否在实践中通过任何体面的实现来执行?假设你只针对成熟的,实现良好的编译器而不关心为模糊平台编写的原始编译器的绝对最大可移植性,那么在C中依赖尾调用是否合理呢?

另外,将尾部呼叫优化留在标准之外的理由是什么?

AnT*_*AnT 28

像"C不执行尾部调用消除"这样的语句没有任何意义.正如你自己正确地指出的那样,这样的事情完全取决于实现.是的,任何体面的实现都可以轻松地将尾递归转换为[相当于]一个循环.当然,C编译器通常不会对优化程序以及每个特定代码段中不会发生的优化提供任何保证.你必须编译它并亲自看看.


Dob*_*eer 6

虽然现代编译器可以在开启优化时进行尾部调用优化,但是调试版本可能会在没有它的情况下运行,因此您可以获得堆栈跟踪和进入/退出代码以及类似的奇妙事情.在这种情况下,不希望尾调用优化.

由于尾调用优化并不总是令人满意,因此将其强制命令编译器编写器是没有意义的.


sta*_*ica 5

我认为,只有在预期或需要大量递归的情况下,才需要保证尾部调用优化。也就是说,使用鼓励或强制执行功能性编程风格的语言。(使用这些类型的语言,您可能会发现不鼓励forwhile不鼓励使用循环,或者将循环视为不优雅的语言,或者甚至完全不鼓励使用循环,因此出于所有这些原因,您可能会求助于递归,甚至更多。)

显然,C编程语言(IMHO)在设计时并未考虑函数式编程。有各种循环结构一般用于支持递归:fordo .. whilewhile。用这种语言,在标准中规定尾部调用优化没有多大意义,因为并不严格要求保证工作程序。

再次将它与没有while循环的功能编程语言进行对比:这意味着您将需要递归;反过来,这意味着该语言必须确保在多次迭代中,堆栈溢出不会成为问题;因此,这种语言的官方标准可能会选择规定尾部呼叫优化。


PS:请注意我的观点略有瑕疵尾调用优化。到最后,我提到堆栈溢出。但是谁说函数调用总是需要堆栈呢?在某些平台上,函数调用可能以完全不同的方式实现,并且堆栈溢出甚至都不会成为问题。这将是反对在标准中规定尾部调用优化的另一个论点。(但是请不要误会我的意思,即使没有堆栈,我也可以看到这种优化的优点!)

  • 无论实施哪种功能,一般情况下,始终需要保存和恢复某些状态。因此,总会有一些函数,使得太多的嵌套函数调用填满了用于存储此状态的可用内存。为此的常规数据结构是固定存储块中的堆栈,但是可以不同地完成。消除尾部调用可以避免某些函数的保存和恢复,但是调用两次的非平凡函数将需要存储第二个调用的状态。 (4认同)