C语言中的尾调用优化是相对较新的特性。
Tail-call optimization in C is relatively recent

原始链接: https://lwn.net/Articles/1034703/

在这篇文章中,Anton 讨论了 C 编译器中尾调用优化(TCO)的演变。从历史上看,C 语言的调用约定因要求调用者负责栈清理而阻碍了 TCO 的实现,导致无法进行有效优化。虽然早期版本的 GCC 在间接调用方面存在显著局限,但现代编译器如 GCC 和 Clang 现已实现了强大的 TCO 支持。 在反思近期对“复制与修补”(Copy-and-Patch)编译的研究时,Anton 指出,现代 TCO 能力现已允许生成超过 10 万个代码片段,这远超传统基于“goto *”的分发系统的限制。作者提到,虽然他们的项目 Gforth 尚未实现这些先进技术,但他们对 Python 社区成功采用该方法以提升性能表示祝贺。

这篇 Hacker News 的讨论围绕一篇关于 C 语言尾调用优化(TCO)历史的 LWN 文章展开,重点探讨了 GCC 编译器中的实现。用户们讨论了追溯到 21 世纪初的这项实现是否应被视为“近期”技术,并指出 ML 等语言更早便已支持 TCO。 主要观点包括: * **技术局限性:** 参与者强调,早期的 GCC 实现存在显著限制,例如无法处理间接调用,而这对于某些编程模式至关重要。 * **语言对比:** 评论者将 C 语言的实现与 JavaScript(TCO 被加入后又被移除)以及 Common Lisp(缺乏强制性 TCO 常使 Scheme 程序员受阻)进行了对比。 * **元评论:** 除了技术讨论外,用户还批评了现代网络写作风格,认为其过度追求“互动”和占用读者时间,而非提供清晰、简洁的信息。 总的来说,该讨论串将 TCO 视为各个编程语言生态系统中长期存在的争议点和技术复杂性问题。
相关文章

原文
Posted Aug 21, 2025 22:11 UTC (Thu) by anton (subscriber, #25547)
Parent article: Python, tail calls, and performance

Actually tail calls in C have not been around forever. The C calling convention has been that the callee does not remove any stuff the caller has put on the stack. The caller could see the declaration int f();, the actual call could have n>0 arguments, and the actual function could have m≤n parameters. That would not always work if the callee removed the arguments.

So the caller had to remove the arguments between the call and the following return, turning the call into a non-tail call.

When I looked in 1994 at the C compilers of the day, they did not perform tail-call optimization for the kind of usage shown in the article. In 2001 Mark Probst implemented tail-call optimization in GCC with a separate calling convention; he lists the limitations of the then-existing tail-call optimization in GCC in section 6.4, among them: "It cannot handle indirect calls" (which would have been used in tail calls for interpreter dispatch).

I have not looked at the issue since then (GCC's goto * was good enough (well, mostly)), and I had not much reason for assuming that something had changed wrt to GCC support for tail-calls (although one release note mentioned sibcalls, and I remember thinking that I should be checking that out.

Anyway, last year I read the paper on "Copy-and-Patch Compilation" by Xu and Kjolstad, and they use tail-call optimization. In any case, after reading that paper, I made some tests if gcc and clang can do tail-call optimization for the kind of tail calls shown in the article. And it works. And Xu and Kjolstad report that they use 100,000 code snippets, whereas we limit ourselves in Gforth to <2000 (for VM instructions, stack caching variations thereof, static superinstructions etc.). Being able to do 100,000 would allow us to use techniques that need too many different code snippets to be usable in a goto *-based system.

We have not gotten around to putting this into Gforth yet, so congratulations to the Python community for being there first.


联系我们 contact @ memedata.com