我只是在那里正在讨论的C代码以下两个peices讨论:'聪明'是GCC的尾巴呼叫优化?
for循环:
#include <stdio.h>
#define n (196607)
int main() {
long loop;
int count=0;
for (loop=0;loop<n;loop++) {
count++;
}
printf("Result = %d\n",count);
return 0;
}
递归:
#include <stdio.h>
#define n (196607)
long recursive(long loop) {
return (loop>0) ? recursive(loop-1)+1: 0;
}
int main() {
long result;
result = recursive(n);
printf("Result = %d\n",result);
return 0;
}
在看到这个代码,我看到了recursive(loop-1)+1
并认为“啊,这不是尾递归调用”,因为它有工作在调用recursive
后做的是完整的;它需要增加返回值。
果然,没有优化,递归码触发栈溢出,如你所愿。
与-O2
标志然而,没有遇到堆栈溢出,我认为堆栈被重用,而不是越来越多地推入堆栈 - 这是tco。
GCC可以明显发现这个简单的例子(+1返回值),并优化它,但多远它去?
什么都可以用TCO优化什么GCC的限制,当递归调用是不被执行的最后一个操作?
附录: 我写了一个完全尾递归的return function();
版本的代码。 包装纸上面与9999999个迭代循环,我想出了以下时序:
$ for f in *.exe; do time ./$f > results; done
+ for f in '*.exe'
+ ./forLoop.c.exe
real 0m3.650s
user 0m3.588s
sys 0m0.061s
+ for f in '*.exe'
+ ./recursive.c.exe
real 0m3.682s
user 0m3.588s
sys 0m0.093s
+ for f in '*.exe'
+ ./tail_recursive.c.exe
real 0m3.697s
user 0m3.588s
sys 0m0.077s
所以(当然简单,并没有很严格)基准测试表明,它确实似乎是在相同的顺序所用的时间。
编译器可能只是内联函数而不是使用尾递归。使用'-S'标志编译程序并查看汇编代码的外观。 –
我同意@squeamishossifrage。不要启用优化,然后假设编译器做了什么。你可能会感到惊讶,这是毫无意义的。 – unwind