我只是在那裏正在討論的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