尾递归优化本质是编译器将尾位置的自身调用复用当前栈帧转为循环,避免栈溢出;要求递归调用为函数最后动作且无后续计算,需用累加参数改写如factorial(n, acc=1)。
尾递归优化(Tail Call Optimization,TCO)不是C++标准强制要求的特性,而是编译器在满足特定条件时,将尾递归函数自
动转换为迭代形式的优化行为。它的核心在于:当函数的最后一个动作是调用自身(即“尾位置调用”),且不依赖当前栈帧的局部变量或返回地址做后续计算时,编译器可以复用当前栈帧,而不是压入新栈帧。这样递归深度再大,栈空间也只占用常数级别(O(1)),避免栈溢出。
尾递归要求递归调用必须是函数体中最后执行的语句,并且其返回值直接作为本层函数的返回值——不能有“调用后还要乘个系数”或“加个常量”这类操作。常见错误写法如 return n * factorial(n-1) 不是尾递归,因为乘法发生在递归返回之后。
factorial(n, acc = 1) { return n
光写对形式还不够,得让编译器真正优化。GCC/Clang 在 -O2 或更高优化等级下通常会启用 TCO(对符合尾调用条件的函数)。你可以通过以下方式确认:
g++ -S -O2 foo.cpp,若尾递归函数内出现 jmp(而非 call)跳转回自身,说明已优化为循环n = 1000000)看是否栈溢出;不溢出且耗时稳定,大概率已优化-O0)默认关闭 TCO,调试时可能栈溢出,但发布版正常由于 C++ 标准不保证 TCO,依赖它存在可移植性风险(比如 MSVC 对尾递归优化支持较弱)。对可靠性要求高的场景,建议主动把尾递归逻辑转成 while 循环:
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }while (b != 0) { int t = b; b = a % b; a = t; } return a;