尾调用优化是否适用于对返回 void 的函数的递归调用?例如我有一个函数void fun()
void fun()
{
...
...
...
fun();
}
这里编译器不会知道,调用 fun() 是最后一条语句。那么尾调用优化是否只针对返回一些值的函数?
尾调用优化是否适用于对返回 void 的函数的递归调用?例如我有一个函数void fun()
void fun()
{
...
...
...
fun();
}
这里编译器不会知道,调用 fun() 是最后一条语句。那么尾调用优化是否只针对返回一些值的函数?
答案是肯定的,它可以,但编译器没有义务这样做。是否这样做在很大程度上取决于函数、编译器和选择的优化级别。如果您担心特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集。
更具体地说,GCC(至少是使用 LLVM 作为后端的 Apple 版本)将为至少一些返回void
优化级别-O1
或更高级别的函数生成尾调用优化代码。
一些测试代码:
/* Fills an array with a single value, recursively with side effects */
void fillarray(int val, int* curr, int* end)
{
if (curr==end) return;
*curr = val;
fillarray(val,curr+1,end);
}
使用最少的优化 ( -O1
),编译为程序集 ( gcc -O1 -S test.c
) 会产生一个很好的尾调用优化函数:
_fillarray:
pushq %rbp
movq %rsp, %rbp # set up the stack
cmpq %rdx, %rsi # early exit if beg == end
je LBB1_2
LBB1_1:
movl %edi, (%rsi) # *curr = val
addq $4, %rsi # curr++
cmpq %rsi, %rdx # TAIL CALL optimization is here
jne LBB1_1 # if curr != end, go to LBB1_1
LBB1_2:
popq %rbp # restore the stack and exit
ret
(注意:我已经删除了一些不必要的标签和对齐语句,它们会混淆程序集的结构)。
此外,当关闭优化 ( -O0
) 时,生成的代码是递归的(不是尾调用优化的)。