C tail call optimization

后端 未结 8 812
陌清茗
陌清茗 2021-01-31 16:25

I often hear people say that C doesn\'t perform tail call elimination. Even though it\'s not guaranteed by the standard, isn\'t it performed in practice by any decent implement

相关标签:
8条回答
  • 2021-01-31 16:58

    The language standard defines how the language behaves, not how compilers are required to be implemented. Optimization isn't mandated because it isn't always wanted. Compilers provide options so that the user can enable optimizations if they so desire them, and can likewise turn them off. Compiler optimization can affect the ability to debug code (it becomes harder to match C to assembly in a line-by-line fashion), so it makes sense to only perform optimization at the user's request.

    0 讨论(0)
  • 2021-01-31 17:03

    It is common for compilers to recognize situations where a function won't need to do anything after calling another, and replace that call with a jump. Many cases where that can be done safely are easy to recognize, and such cases qualify as "safe low-hanging fruit". Even on compilers that can perform such optimization, however, it may not always be obvious when it should or will be performed. Various factors may make the cost of a tail call greater than that of a normal call, and these factors may not always be predictable. For example, if a function ends with return foo(1,2,3,a,b,c,4,5,6);, it may be practical to copy a, b, and c into registers, clean up the stack and then prepare the arguments for passing, but there may not be enough registers available to handle foo(a,b,c,d,e,f,g,h,i); likewise.

    If a language had a special "tail call" syntax that required that compilers given that make a tail call if at all possible, and refuse compilation otherwise, code could safely assume such functions could be nested arbitrarily deep. When using ordinary call syntax, however, there's no general way to know whether a compiler would be able to perform a tail call more cheaply than an "ordinary" one.

    0 讨论(0)
  • 2021-01-31 17:06

    I think that tail call optimizations need to be guaranteed only where a lot of recursion is anticipated or required; that is, in languages that encourage or enforce a functional programming style. (With these kinds of languages, you may find that for or while loops are either strongly discouraged, perceived as inelegant, or probably even completely absent from the language, so you would resort to recursion for all these reasons, and probably more.)

    The C programming language (IMHO) clearly was not designed with functional programming in mind. There's all kinds of loop constructs that are generally used in favour of recursion: for, do .. while, while. In such a language, it wouldn't make much sense to prescribe tail call optimization in a standard, because it's not strictly required to guarantee working programs.

    Contrast this again with a functional programming language that doesn't have while loops: This means you will need recursion; which in turn means that the language must make sure that, with many iterations, stack overflows won't become a problem; thus the official standard for such a language might choose to prescribe tail call optimization.


    P.S.: Note a slight flaw in my argument for tail call optimization. Towards the end of, I mention stack overflows. But who says that function calls always require a stack? On some platforms, function calls might be implemented in a totally different way, and stack overflows would never even be a problem. This would be yet another argument against prescribing tail call optimization in a standard. (But don't get me wrong, I can see the merits of such optimizations, even without a stack!)

    0 讨论(0)
  • 2021-01-31 17:12

    Statements like "C doesn't perform tail call elimination" make no sense. As you correctly noted yourself, things like this depend entirely on the implementation. And yes, any decent implementation can easily turn tail-recursion into [an equivalent of] a cycle. Of course, C compilers do not normally give any guarantees about what optimizations will and what optimizations will not happen in each particular piece of code. You have to compile it and see for yourself.

    0 讨论(0)
  • 2021-01-31 17:15

    For those who like proof by construction, here is godbolt doing a nice tail call optimisation and inline: https://godbolt.org/z/DMleUN

    However, if you crank the optimization to -O3 (or no doubt if you wait a few years or use a different compiler), the optimisation totally removes the loop/recursion.

    Here is an example that optimizes down to a single instruction even with -O2: https://godbolt.org/z/CNzWex

    0 讨论(0)
  • 2021-01-31 17:16

    To answer you last question: The standard should definitely not make any statements about optimization. There may be environments where it is more or less difficult to implement.

    0 讨论(0)
提交回复
热议问题