天天看点

c语言中的函数间的跳转函数setjmp和longjmp

http://yijiuzai.blog.163.com/blog/static/10375672720105197114165/

我们知道,在c语言中我们可以使用goto语句在一个函数中进行跳转,例如一个常用的goto方式为:

......

//分配资源

......

if error1

   goto error;

if error2

   goto error;

........

error:

    ......

    // 释放资源

    ......

但是goto语句也只限于一个函数内,不能进行函数间的跳转。在c语言中,进行函数间的跳转使用setjmp和longjmp函数。

为什么要有个函数间的跳转呢,这是因为,如果我们在调用函数时,函数的调用的嵌套的层次很深的话,如果出错,那么一层一层的返回和判断就很麻烦,所以,如果出错,就可以直接返回到最上面的调用的函数就会很方便。

我们来看一下这两个函数怎么使用,首先看一下这两个函数的原型:

#include <setjmp.h>

int setjmp(jmp_buf env);   //直接调用则返回0,如从longjmp调用则返回非0

int longjmp(jmp_buf env, int val);

jum_buf是一个类型,其中env存储了一些longjmp调用返回用来恢复栈状态的所有信息。longjmp中的env和setjmp中的env是同一个。val是程序员自定义的直,这个值用在setjmp的返回值中,这样我们就可以知道是在哪个的longjmp跳转回来的。另外,由于在不同的函数间调用setjmp和longjmp,而这两个函数要公用一个env变量,所以把env定义为一个全局变量。

下面我们看一个简单的例子:

view plaincopy to clipboardprint?

#include <stdio.h>   

#include <setjmp.h>   

jmp_buf jmpbuffer;   

void func1();   

void func2();   

int main(void)   

{   

    printf("in main function! ");   

    if(setjmp(jmpbuffer) != 0)   

    {   

        printf("get the error from jump return! ");   

        return -1;   

    }   

    func1();   

    printf("main function end! ");   

    return 0;   

}   

void func1()   

{   

    printf("in func1 function! ");   

    func2();   

}   

void func2()   

{   

    printf("in func2 function! ");   

    longjmp(jmpbuffer, 1);   

}  

#include <stdio.h>

#include <setjmp.h>

jmp_buf jmpbuffer;

void func1();

void func2();

int main(void)

{

 printf("in main function! ");

 if(setjmp(jmpbuffer) != 0)

 {

  printf("get the error from jump return! ");

  return -1;

 }

 func1();

 printf("main function end! ");

 return 0;

}

void func1()

{

 printf("in func1 function! ");

 func2();

}

void func2()

{

 printf("in func2 function! ");

 longjmp(jmpbuffer, 1);

}

编译:gcc main.c

运行:./a.out

输出:

in main function!

in func1 function!

in func2 function!

get the error from jump return!

我们在程序中可以看到,我们在main函数用setjmp中设置了一个接受跳转返回的点,在func2函数中用longjmp跳转返回。

在跳转返回后,我们直接退出函数,那么后面的

    printf("main function end! ");

    return 0;

这两个语句将得不到执行。

前面我们说过longjmp函数中的val参数用来確定我们的jump是在哪产生的,下面我们修改一下前面的例子,看看怎样区别不同的跳转点。

view plaincopy to clipboardprint?

#include <stdio.h>   

#include <setjmp.h>   

jmp_buf jmpbuffer;   

void func1();   

void func2();   

int main(void)   

{   

    printf("in main function! ");   

    int errNum = 0;   

    errNum = setjmp(jmpbuffer);   

    if(errNum != 0)   

    {   

        if (errNum == 1)   

            printf("get the error from func1 function ! ");   

        if (errNum == 2)   

            printf("get the error from func2 function ! ");   

        return -1;   

    }   

    func1();   

    printf("main function end! ");   

    return 0;   

}   

void func1()   

{   

    printf("in func1 function! ");   

    longjmp(jmpbuffer, 1);   

    func2();   

}   

void func2()   

{   

    printf("in func2 function! ");   

    longjmp(jmpbuffer, 2);   

}  

#include <stdio.h>

#include <setjmp.h>

jmp_buf jmpbuffer;

void func1();

void func2();

int main(void)

{

 printf("in main function! ");

 int errNum = 0;

 errNum = setjmp(jmpbuffer);

 if(errNum != 0)

 {

  if (errNum == 1)

   printf("get the error from func1 function ! ");

  if (errNum == 2)

   printf("get the error from func2 function ! ");

  return -1;

 }

 func1();

 printf("main function end! ");

 return 0;

}

void func1()

{

 printf("in func1 function! ");

 longjmp(jmpbuffer, 1);

 func2();

}

void func2()

{

 printf("in func2 function! ");

 longjmp(jmpbuffer, 2);

}