关于GCC手册,
-foptimize同胞通话
优化兄弟和尾部递归调用。
例如,我知道尾递归调用
int sum(int n){return n == 1? 1:n + sum(n-1); }
然而,兄弟姐妹的意思是什么?
如果它们共享返回类型的相同结构等价,以及匹配其参数的空间要求,则编译器将两个函数视为兄弟。
必须是这样的:
int ispair(int n) { return n == 0 ? 1 : isodd(n-1); }
int isodd(int n) { return n == 0 ? 0 : ispair(n-1); }
通常,如果函数调用是最后一个句子,那么它可以被跳转替换。
void x() { ......; y(); }
在这种情况下,y()
可以用跳转(或内联函数)代替,而不是使用标准函数调用。
如果函数调用是在另一个函数中执行的最后一个操作,则称其为尾调用。
该名称源于函数调用出现在其他函数的尾部位置的事实。
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.
}
每个尾递归调用都是一个兄弟调用,因为定义意味着每个函数都是它自己的兄弟。
由于堆叠占用面积相同,更换堆叠框架变得相对容易。编译器编写者不必调整堆栈帧的大小,并且就地变异变得简单。