在一系列函数调用中,例如
main() --> A() --> B()-->C();
被调用函数完成后,通常会返回到调用函数,例如C()
返回到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");
}
我想跳过从A()
返回到函数B()
的过程,以使printf("exit A()\n");
无法执行,并给我以下结果:
enter A()
enter B()
exit B()
答案 0 :(得分:3)
在检查@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
中
结构和returns 0
。
程序继续调用A()
,后者调用B()
。
而
在函数B()
中,如果用户选择不返回long jump
,则函数将
显示正常的返回顺序。
如果用户选择按longjmp(env,1234)
返回,
执行将返回到带有nonzero
值的最后保存的环境。
在
在这种情况下,它会导致B()
绕过main()
直接返回A()
。
原理
long jump
非常简单。函数完成后,将由
(caller_EIP, caller_EBP)
在当前堆栈帧中,
如果将(caller_EIP, caller_EBP)
替换为
(saved_EIP, saved_EBP)
按照调用顺序,执行将直接返回到该函数。
另外
到(saved_EIP, saved_EBP)
,setjmp()
可能还会保存CPU的通用寄存器,并且
原始的ESP
,以便longjmp()
可以还原返回的完整环境
功能。
跳远可用于中止调用序列中的函数,从而导致 从先前保存的已知环境中恢复执行。
虽然很少使用 在用户模式程序中,这是系统编程中的常见技术。
例如, 它可能会在信号捕获器中用于绕过导致 异常或陷阱错误。
您可以检查this也很好