在一系列函数调用中,例如
main() --> A() --> B()-->C();
当一个被调用的函数完成时,它通常会返回到调用函数,例如C()
返回B()
,B()
返回A()
等
我想知道是否也可以直接返回调用序列中较早的函数
所以 C()
返回到 main()
并跳过 B()
和 A()
如果可以的话我该怎么做?你能解释一下它是如何工作的以及它何时在现实中使用吗?
这是我的代码
#include <stdio.h>
int A(void);
int B(void);
void main(void )
{
A();
}
int A()
{
printf("enter A()\n");
B();
printf("exit A()\n");
}
int B()
{
printf("enter B()\n");
printf("exit B()\n");
}
并且我想跳过从 B()
返回函数 A()
以便 printf("exit A()\n");
不会执行并给我这个结果:
enter A()
enter B()
exit B()
最佳答案
在检查所有内容之前,@PeterCordes 以多种方式回答了问题
好的,让我们开始吧:
这种类型的东西可以使用称为long jump
的东西来完成,所以你的代码在编辑后看起来像这样:
#include <stdio.h>
#include <setjmp.h>//c standard library header
jmp_buf env; // for saving longjmp environment
main()
{
int r, a=100;
printf("call setjmp to save environment\n");
if ((r=setjmp(env)) == 0){
A();
printf("normal return\n");
}
else
printf("back to main() via long jump, r=%d a=%d\n", r, a);
}
int A()
{
printf("enter A()\n");
B();
printf("exit A()\n");
}
int B()
{
printf("enter B()\n");
printf("long jump? (y|n) ");
if (getchar()=='y')
longjmp(env, 1234);
printf("exit B()\n");
}
让我们了解一下刚刚发生了什么
在上面的程序中,setjmp()
将当前执行环境保存在一个jmp_buf
中
结构,返回 0
。
程序继续调用 A()
,后者调用 B()
。
同时
在函数B()
中,如果用户选择不通过long jump
返回,函数将
显示正常的返回序列。
如果用户选择通过longjmp(env,1234)
返回,
执行将返回到上次保存的具有非零
值的环境。
在
在这种情况下,它会导致 B()
绕过 A()
直接返回到 main()
。
原则
跳远
非常简单。当一个函数完成时,它返回
(caller_EIP, caller_EBP)
在当前堆栈框架中,
如果我们将 (caller_EIP, caller_EBP)
替换为
(saved_EIP, saved_EBP)
较早的函数
在调用序列中,执行将直接返回到该函数。
此外
到(saved_EIP, saved_EBP)
,setjmp()
也可以保存CPU的通用寄存器和
原始的ESP
,让longjmp()
可以还原返回的完整环境
功能。
长跳转可用于中止调用序列中的函数,导致 从先前保存的已知环境恢复执行。
虽然很少用 在用户模式程序中,它是系统编程中的常用技术。
例如, 它可以用在信号捕捉器中以绕过导致的用户模式功能 异常或陷阱错误。
可以查看this也不错
关于c - 在调用者的返回序列中跳过函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51914598/