尾部调用
如果函数调用是另一个函数中执行的最后一个操作,则称为尾调用。
该名称源于该函数调用出现在其他函数的尾部位置。
int foo(int a, int b) {
// some code ...
return bar(b); // Tail call which is neither sibling call nor tail recursive call.
}
bar
出现在尾部位置foo
。拨电至bar
是尾调用。
尾递归调用
尾递归调用是尾调用的一种特殊情况,其中被调用函数与调用函数相同。
int foo(int a, int b) {
if (a > 0) {
return foo(a - 1, b + 1); // Tail recursive call
} else {
return b;
}
}
兄弟姐妹来电
同级调用是尾调用的另一种特殊情况,其中调用者函数和被调用者函数不需要相同,但它们具有兼容的堆栈占用空间。
这意味着两个函数的返回类型必须相同,并且传递的参数必须占用相同的堆栈空间。
int foo(int a, int b) {
// some code ...
return bar(a - 1, b); // Sibling call, also a tail call, but not a tail recursive call.
}
每个尾递归调用都是同级调用,因为定义意味着每个函数都是其自身的同级函数。
为什么要区分?
由于堆栈占用空间相同,更换堆栈框架变得相对容易。
编译器编写者不必调整堆栈帧的大小,并且就地突变变得简单。