11

我正在尝试尽可能多地用 C 编写函数式程序。我知道像 GCC/Clang 这样的编译器会默默地进行尾调用优化,但不能保证。是否有任何选项可以强制对编译器进行尾调用优化?(当然,只有在它自己的末尾才被调用)

4

7 回答 7

10

Clang 13 “musttail”属性强制尾递归函数中的尾调用优化,即使优化被禁用。

https://clang.llvm.org/docs/AttributeReference.html#musttail

用法:

int f(int x) {
  ...
  __attribute__((musttail)) return f(x-1);
}
于 2021-05-05T08:13:43.610 回答
5

Clang 根本没有做任何优化。有一个 LLVM 通行证tailcallelim可以做你想做的事(但不能保证)。您可以使用opt.

于 2011-01-24T17:41:45.130 回答
3

我不认为它真的强制执行它,但你可以-foptimize-sibling-calls在使用gcc. 如果您使用-O2,-O3或,它会自动启用-Os

一般来说,我建议不要在 C 中过度使用递归。如果你真的想做 fp,请选择一种函数式语言。在某些情况下它是合适的,例如快速排序,buf,如果您习惯于使用递归而不是循环,那么您很有可能会破坏堆栈。

于 2019-09-12T14:22:22.450 回答
2

元答案:

从函数式语言过渡到 C 语言有一些有用的教训:使用小函数,使用不会改变全局变量或输入参数的函数,不要害怕函数指针。但是你在这里可以合理地做的事情是有限的,依赖尾调用消除('尾调用优化'并不是真正正确的术语)可能超出了有用的范围。你不能强迫编译器使用这个策略,即使你可以,生成的 C 语言也会非常单调,并且很难被其他人阅读,包括你未来的自己。

发挥语言的优势。C某些事情有好处,因此以良好的 C 风格将其用于那些事情。如果您想要不同的优势,或者如果您想使用函数式风格(绝妙的决定!),请使用函数式语言。

于 2014-07-23T19:16:45.960 回答
1

Alpha 和 i386 的 GCC 扩展描述如下:

Mark Probst,2001 年的C 语言中的适当尾递归(文凭论文) 。

于 2021-04-20T21:26:50.240 回答
0

实际上,很多 C 编译器已经为您处理了这个问题。正如 eq 所提到的,您最好让编译器处理大部分这些事情,而不是尝试创建在其他地方不起作用的优化。很多时候,即使您设置了优化标志,您也会发现实际上并没有性能差异。

于 2011-01-24T17:41:21.047 回答
-1

如果它确实是尾调用,那么 while 循环或 goto 看起来与递归调用没有太大区别。只需更新所有变量,而不是将它们作为参数传递。AFAIK 这是 C 语言中在所有优化级别控制堆栈使用的唯一跨平台方式。它实际上也更具可读性,因为您有一个初始化函数,然后是循环,这是非常惯用的。尾递归版本需要两个函数,一个用于初始化,一个用于递归部分。

于 2016-01-20T17:09:12.847 回答