Table of Contents

C tail call optimization

C tail call optimization (TCO) is a compiler optimization where a function's final call becomes a jump, reusing the same stack frame. Recursive functions calling themselves at the end convert from O(n) stack space to O(1). Optimizers enable TCO with -O2 or higher; not guaranteed.

Write tail-recursive functions to potentially benefit from TCO; don't depend on it for correctness.

Example

// compile: gcc -O2 -o tail_call tail_call.c
// run: ./tail_call
// description: tail call optimization for recursion
 
#include <stdio.h>
 
// Tail-recursive factorial (compiler may optimize)
long factorial_tail(int n, long acc) {
    if (n <= 1)
        return acc;
    return factorial_tail(n - 1, acc * n);  // Tail call
}
 
// Non-tail-recursive factorial (can't optimize)
long factorial_normal(int n) {
    if (n <= 1)
        return 1;
    return n * factorial_normal(n - 1);  // Not tail call
}
 
// Tail-recursive sum
long sum_tail(int n, long acc) {
    if (n <= 0)
        return acc;
    return sum_tail(n - 1, acc + n);  // Tail call
}
 
// Fibonacci tail-recursive (accumulator pattern)
long fib_tail(int n, long a, long b) {
    if (n == 0) return a;
    if (n == 1) return b;
    return fib_tail(n - 1, b, a + b);  // Tail call
}
 
int main() {
    printf("Factorial(10) = %ld\n", factorial_tail(10, 1));
    printf("Sum(100) = %ld\n", sum_tail(100, 0));
    printf("Fib(20) = %ld\n", fib_tail(20, 0, 1));
 
    printf("Large factorial(1000) = %ld\n", factorial_tail(1000, 1));
 
    return 0;
}

Common patterns

Tail call definition:

Compiler requirements:

Accumulator pattern:

Benefits:

When TCO matters:

Limitations:

Debugging note:

Alternatives: