C语言的非局部跳转:setjmp和longjmp

来源:互联网 发布:人类文明史图鉴淘宝 编辑:程序博客网 时间:2024/05/16 04:41

        C语言中有一个goto语句,其可以结合标号实现函数内部的任意跳转(通常情况下,很多人都建议不要使用goto语句,因为采用goto语句后,代码维护工作量加大)。另外,C语言标准中还提供一种非局部跳转“no-local goto”,通过setjmp和longjmp函数来实现。

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

 1 #include <stdio.h> 2 #include <setjmp.h> 3  4 jmp_buf jump_buffer; 5  6 void func(void) 7 { 8          printf("Before calling longjmp\n"); 9          longjmp(jump_buffer, 1);10          printf("After calling longjmp\n");11 }12 void func1(void)13 {14          printf("Before calling func\n");15          func();16          printf("After calling func\n");17 }18 int main()19 {20          if (setjmp(jump_buffer) == 0){21                    printf("first calling set_jmp\n");22                    func1();23          }else {24                    printf("second calling set_jmp\n");25          }26          return 0;27 }

代码的运行结果如下

lienhua34@lienhua34-laptop:~/program/test$ ./test
first calling set_jmp
Before calling func
Before calling longjmp
second calling set_jmp

        通过上面这个简单例子的运行结果可以看出。main函数运行的setjmp()宏调用,将当前程序点的系统状态信息保存到全局变量jump_buffer中,然后返回结果0。于是,代码打印出字符串”first calling set_jmp”,然后调用函数func1()。在函数func1中,先打印字符串”Before calling func”,然后去调用函数func()。现在程序控制流转到func函数中,函数func先打印字符串“Before calling longjmp”,然后调用函数longjmp。这时候关键点到了!!!longjmp函数将main函数中setjmp()宏调用设置在全局变量jump_buffer中的系统状态信息恢复到系统的相应寄存器中,导致程序的控制流跳转到了main函数中setjmp()宏调用所在的程序点,此时相当于第二次进行setjmp()宏调用,并且此时的setjmp()宏调用的返回不再是0,而是传递给函数调用longjmp()的第二个参数1。于是程序控制流转到main函数中if语句的else部分执行,打印字符串“second calling set_jmp“。最后,执行main函数中的语句“reture 0;”返回,程序运行结束退出。

       从上面的运行过程,我们可以看出在longjmp()函数调用处的程序点嵌套在三层函数调用中:main, func1和func,但是longjmp()函数调用导致程序控制流跳过函数调用func和func1,直接回到main函数中setjmp()宏调用所在的程序点,然后执行main函数中后续的语句,从而忽略了函数func1和func中后续的语句部分。这就是非局部跳转。

0 0