使用setjmp()和longjmp()执行非局部跳转

1.简述

库函数setjmp和longjmp可以实现跳转到当前执行函数之外的某个位置,虽然此功能就像goto语句一样使程序不好维护,但是当一个深度嵌套的函数中发生了错误,需要放弃当前任务,从多层函数调用中返回到较高层,此时setjmp和longjmp就派上了用场

2.函数具体形式

#include<setjmp.h>
int setjmp(jmp_buf env);
void longjmp(jmp_buf env,int val);
setjmp()函数的位置为调用longjmp()函数后的跳转目标,可以这样认为,当调用了longjmp()后程序好像执行了回退功能一样,又从setjmp()的位置开始执行了。

setjmp()和longjmp()调用的参数env是一个全局变量,它里面保存了setjmp()当前执行环境的各种信息,之后调用的longjmp()也是这个全局变量env,env中保存了调用setjmp()函数的当前进程的信息,还保存了程序计数寄存器(指向当前正在执行的机器指令)和栈指针寄存器(标记栈顶的)的副本,正是这些信息可以使调用longjmp()时完成俩个关键步骤:
(1)将longjmp()调用的函数与之前调用setjmp()的函数之间的函数栈帧(保存函数实参,局部变量,函数链接信息等)从函数栈中脱离,通过栈指针寄存器重置为env保存的值(此时栈顶就是调用setjmp()函数的栈帧了)
(2)重置程序计数寄存器,使程序可以从初始的setjmp()处开始执行,此功能是通过env参数中保存的值来实现的

3具体实例

#include<stdio.h>
#include<setjmp.h>


static jmp_buf env;

void f2(void)
{
    longjmp(env,2);
}

void f1(int argc)
{
    if(argc == 1)
    {
        longjmp(env,1);
    }
    f2();
}

int main(int argc,char **argv)
{
    switch(setjmp(env))
    {
        case 0:
            printf("Calling f1 after the initial setjmp\n");
            f1(argc);
            break;
        case 1:
            printf("jumped from f1\n");
            break;
        case 2:
            printf("jump from f2\n");
            break;
    }

    return 0;
}

该程序通过setjmp的初始调用建立了一个跳转目标,通过swich判断setjmp()是初次调用函数二次调用,具体的运行结果由读者自己去测试

4.总结

setjmp()和longjmp()是一对函数,我们可以使用他们使我们的程序类似回退到我们想回去的地方,setjmp()就是记录我们想要回退的位置的函数,而longjmp()就是触发回退的函数

你可能感兴趣的:(跳转,longjmp)