Optimization void返回型函数的尾部调用优化
尾部调用优化对于返回void的函数的递归调用有效吗?例如,我有一个函数,void fun()Optimization void返回型函数的尾部调用优化,optimization,recursion,Optimization,Recursion,尾部调用优化对于返回void的函数的递归调用有效吗?例如,我有一个函数,void fun() void fun() { ... ... ... fun(); } 在这里,编译器不会知道,调用fun()是最后一条语句。那么尾部调用优化是否只针对返回某些值的函数进行呢?答案是可以,但编译器没有义务这样做。这在很大程度上取决于函数、编译器和所选的优化级别。如果您关心特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集 更具体地说,GCC(至少是使用LLVM作为
void fun()
{
...
...
...
fun();
}
在这里,编译器不会知道,调用fun()是最后一条语句。那么尾部调用优化是否只针对返回某些值的函数进行呢?答案是可以,但编译器没有义务这样做。这在很大程度上取决于函数、编译器和所选的优化级别。如果您关心特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集 更具体地说,GCC(至少是使用LLVM作为后端的苹果版本)将为至少一些返回优化级别
-O1
或更好的void
的函数生成尾部调用优化代码
一些测试代码:
/* 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
),生成的代码是递归的(不是尾部调用优化的)。取决于编译器。你在用哪一个?@RogerLipscombe。但是无论我使用哪种编译器,编译器如何知道它是最后一条语句呢?没有显式的返回,比如返回某个值的函数,比如returing int。,我想知道,返回类型会有什么不同?我的猜测是尾部优化在这种情况下会起作用。编译器可以根据它后面紧跟右大括号的事实推断它是最后一条语句。@shar如果没有显式返回,递归何时结束?