考虑以下功能:
int main()
{
//statement(s);
func1();
//statement(s);
}
void func1()
{
//statement(s);
func2();
//statement(s);
}
void func2()
{
//statement(s);
}
在func2
执行了所有操作后,编译器如何知道返回的位置?我知道控件转移到函数func1
(确切地说是哪个语句),但 编译器知道它?什么告诉编译器返回哪里?
答案 0 :(得分:15)
答案 1 :(得分:3)
实际上,编译器没有运行代码,但是机器运行,并且当它调用新函数时,它存储 next 指令的地址,该指令在当前函数之后执行在堆栈上调用,以便当函数返回时,它可以将其弹回到指令指针(IP)并从那里继续。
为了解释,我简化了一些事情。
答案 2 :(得分:2)
当一个函数被调用时,调用函数中的正确返回地址被放置在某个地方,通常是堆栈,虽然标准没有强制要求,这用于存储返回地址的目的。
编译器有责任确保其调用约定除非出现问题(例如,stack overflow),否则被调用的函数知道如何返回调用函数。
答案 3 :(得分:1)
运行时使用一些称为“调用堆栈”的东西,它基本上保存了在调用函数返回后要调用的下一个语句的地址。因此,当进行函数调用并且在控制跳转到新指令地址之前,调用函数中的下一个指令地址被推送到堆栈。并且对于任何后续对任何函数的调用都会重复此过程。现在为什么只有一堆?因为有必要回到它停止的地步 - 这基本上是'先进先出'行为,而堆栈就是这样做的数据结构。在Visual Studio中调试程序时,您实际上可以查看此调用堆栈 - 有一个名为“调用堆栈”的单独窗口,它显示调用堆栈中放置的地址条目。