出于性能考虑,递归是否被替换成while
循环?我知道代码看起来会丑很多,但让我们看下面的示例:
void print_countdown(long long n) {
if (n!=0) {
printf("Placeholder for a function\n");
print_countdown(n-1);
} else
printf("Done!\n");
}
如果数字是一百万,那么这将有以下开销:
- 1百万份
n
变量的拷贝(从rdi中保存,在递归调用时放回rdi,如果递归工作包括函数调用,则需要放回。否则可以保留在rdi中) call func
push rbp ... pop
函数序言或其他用于堆栈对齐的内容,具体取决于优化级别和编译器选择。
void print_countdown(long long n) {
while (n < MAX_LOOPS) {
if (n!=0) {
printf("Placeholder for a function\n");
n = n-1;
} else
printf("Done!");
}
}
汇编代码(Godbolt)在while
格式下看起来要简单得多,约20行代码,而不是约40行代码。这种循环改写常见吗?在递归函数调用中是否有不能转换为
loop
的情况?
-O3
编译并查看结果。 (但基本上,用 jmp foo 替换 call foo / ret 是标准的尾递归优化。在递归函数中,这将创建一个可以进一步优化的循环。) - Peter Cordes-O3
,我只是为了响应tf3的评论而这么说。(一开始我没有注意到Godbolt链接,因为链接在代码格式上不太明显,而且链接文本没有任何意义。) - Peter Cordes