Optimization void返回型函数的尾部调用优化

Optimization void返回型函数的尾部调用优化,optimization,recursion,Optimization,Recursion,尾部调用优化对于返回void的函数的递归调用有效吗?例如,我有一个函数,void fun() void fun() { ... ... ... fun(); } 在这里,编译器不会知道,调用fun()是最后一条语句。那么尾部调用优化是否只针对返回某些值的函数进行呢?答案是可以,但编译器没有义务这样做。这在很大程度上取决于函数、编译器和所选的优化级别。如果您关心特定函数的这一点,请查看特定编译器在特定优化级别生成的程序集 更具体地说,GCC(至少是使用LLVM作为

尾部调用优化对于返回void的函数的递归调用有效吗?例如,我有一个函数,void fun()

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如果没有显式返回,递归何时结束?