递归消除?
Steve Yegge在博客文章中提到它,我不知道它是什么意思,有人可以填补我吗?
跟尾部呼叫优化是一样的吗?
尾巴消除是一种节省堆栈空间的优化。 它用goto代替函数调用 。 尾递归消除是同样的事情,但增加了函数调用自身的约束。
基本上,如果函数A
所做的最后一件事是return A(params...)
那么可以消除堆栈帧的分配,而是设置适当的寄存器并直接跳转到函数的主体中。
考虑一个(虚构的)调用约定,该约定传递堆栈上的所有参数并返回某个寄存器中的值。
一些函数可以编译成(用虚构的汇编语言):
function:
//Reading params B, C, & D off the stack
pop B
pop C
pop D
//Do something meaningful, including a base case return
...
//Pass new values for B, C, & D to a new invocation of function on the stack
push D*
push C*
push B*
call function
ret
无论上面实际做什么,它都会为每个函数调用占用一个全新的堆栈帧。 然而,由于除了返回之外,在尾部调用之后没有任何操作发生,所以我们可以安全地优化该情况。
导致:
function:
//Reading params B, C, & D off the stack (but only on the first call)
pop B
pop C
pop D
function_tail_optimized:
//Do something meaningful, including a base case return
...
//Instead of a new stack frame, load the new values directly into the registers
load B, B*
load C, C*
load D, D*
//Don't call, instead jump directly back into the function
jump function_tail_optimized
最终结果是一个等价的函数,可以节省大量的堆栈空间,特别是对于导致大量递归调用的输入。
我的回答中有很多想象力,但我认为你可以明白。
从这里:
“...尾递归消除是尾调用消除的一种特殊情况,其中tail调用是对函数本身的调用,在这种情况下,调用可以通过在移动新参数之后跳转到函数的开头来替换到适当的寄存器或堆栈位置......“
来自维基百科:
“...当一个函数被调用时,计算机必须”记住“它被调用的地方,返回地址,以便在调用完成后返回到该位置并返回结果。通常,这些信息被保存在堆栈中,按照它们描述的调用位置的次数,返回一个简单的位置列表。有时候,函数完成所有其他操作后最后一件事是简单地调用一个函数,可能是它本身,然后返回。其结果和尾递归,就没有必要记住我们是从调用的地方-相反,我们可以独自离开堆栈和新调用的函数将直接返回其结果原来的主叫方发起呼叫转换为一个分支 。 或者在这种情况下跳转被称为尾部调用优化请注意,尾部调用不必在源代码中的所有其他语句之后词法上出现;重要的是它的结果立即返回,因为调用函数将会 如果进行优化,我永远不会有机会做任何事情......“
链接地址: http://www.djcxy.com/p/80507.html