如何防止递归功能调用(尾部回复)堆积在堆栈中
How to prevent recursive function call (tail-recursion) from piling up in stack?
当函数在最后一行或使用return
命令中调用自己时,似乎不必将呼叫者放在堆栈中。
我用" GCC"测试了这一理论,发现呼叫者函数仍在堆栈中:
#include <iostream>
void a(int i)
{
std::cout << i << std::endl;
if (i > 0)
a(i - 1);
// Also tested return a(i - 1);
}
int main()
{
a(10);
}
呼叫堆栈:
...
a(int i) (/mnt/temp/hackerrank/src/main.cpp:30)
a(int i) (/mnt/temp/hackerrank/src/main.cpp:30)
a(int i) (/mnt/temp/hackerrank/src/main.cpp:30)
main() (/mnt/temp/hackerrank/src/main.cpp:35)
为什么优化不迫使父母弹出?
根据评论:此主题以"尾部递归"而闻名。
我把它扔进了Godbolt
在GCC(8.3(和Clang(8.0.0(上具有-O3
优化,该功能将其编译为NO-OP函数。令人印象深刻的是,对于MSVC v19.20而言,这甚至是/O2
优化也是如此。
GCC 8.3/clang 8.0.0:
a(int):
ret
msvc v19.20(x64(:
i$ = 8
void a(int) PROC ; a, COMDAT
ret 0
void a(int) ENDP ; a
我也以使榜样非平凡的自由。我从这里使用的代码是:
#include <iostream>
void a(int i)
{
std::cout << "hellon";
if (i > 0)
a(i - 1);
}
启用-O3
优化的GCC截面的编译器输出以下是:
.LC0:
.string "hellon"
a(int):
push rbx
mov ebx, edi
jmp .L3
.L6:
sub ebx, 1
.L3:
mov edx, 6
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
test ebx, ebx
jg .L6
pop rbx
ret
_GLOBAL__sub_I_a(int):
sub rsp, 8
mov edi, OFFSET FLAT:_ZStL8__ioinit
call std::ios_base::Init::Init() [complete object constructor]
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:_ZStL8__ioinit
mov edi, OFFSET FLAT:_ZNSt8ios_base4InitD1Ev
add rsp, 8
jmp __cxa_atexit
从仔细检查中,唯一的call
指令是在IO方法上写下每次迭代中的消息的方法。然后执行test
(if语句(。如果i > 0
,控件会跳起来,将减少i
,然后再次完成。if语句(错误情况(的另一个分支简单地返回(堆栈清理后(。
因此,即使在这个非平凡的示例中,也没有堆叠框架的积累。它是通过jmp
指令执行的,因为(正如您所说的(以前的执行信息无关。
相关文章:
- 算法问题:查找从堆栈中弹出的所有序列
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 堆栈和队列是否像C++中的数组一样传递?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 堆栈中大小变量输入错误 (C++)
- 堆栈问题(平衡表达式问题集)
- C++ 在堆栈中包含多态属性的类对象存储
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 在 C++ 中使用链表进行堆栈
- 变量周围的堆栈'...'已损坏
- 在 gtest 中初始化堆栈上的引用变量的隔离错误
- 如何防止递归功能调用(尾部回复)堆积在堆栈中