根据维基:
来自Wiki的调用者将返回地址压入堆栈,然后调用 子程序,当它完成时,弹出退出呼叫的地址 堆栈并将控制转移到该地址。
图片:
我不太明白这一点。 假设我有一个C程序如下:
#include <stdio.h>
int foo(int x)
{
return x+1;
}
void spam()
{
int a = 1; //local variable
int b = foo(a); //subroutine called
int c = b; //local variable
}
int main()
{
spam();
return 0;
}
我认为调用堆栈应该类似于绘图,如下所示:
<None> means none local variables or params
_| parameters for foo() <int x> |_
top | local of spam() <int c> |
^ | return address of foo() |<---foo() called, when finishes, return here?
| | local of spam() <int b> |
bot | local of spam() <int a> |
_| parameters for spam() <None> |_
| locals of main() <None> |
| return address of spam() |<---spam() called, when finishes, return here?
| parameters for main() <None> |
问题:
根据维基引用的字样,
被调用的子程序,当它完成时,弹出返回地址 调用堆栈并将控制转移到该地址。
1.我的抽签是对吗?
2.如果它是正确的,那么当foo()完成时,它将
将调用堆栈中的返回地址弹出并将控制转移到 那个地址
,但它如何弹出退货地址? 因为当foo完成时,当前堆栈指针指向垃圾邮件的本地, 正确?
更新
如果main()看起来像这样:
int main()
{
spam();
foo();
}
然后调用堆栈应该是什么样的?
答案 0 :(得分:15)
您的绘图不正确。函数的本地堆栈变量都低于任何返回地址。否则,正如您所观察到的那样,当您调用函数时,本地人会迷失。
应该是这样的:
| parameters for foo() <int x> |
| return address of foo() |
| local of spam() <int c> |
| local of spam() <int b> |
| local of spam() <int a> |
| parameters for spam() <None> |
| return address of spam() |
| locals of main() <None> |
| parameters for main() <None> |
我认为令人困惑的是,您认为变量声明被视为语句并按顺序执行。实际上,编译器通常会分析一个函数来决定所有局部变量需要多少堆栈空间。然后它发出代码来相应地调整堆栈指针,并在进入函数时进行调整。然后,对其他函数的任何调用都可以推入堆栈而不会干扰此函数的堆栈帧。