非本地跳转

   首先介绍下与非本地跳转的对应的本地跳转,本地跳转指的是类似于goto语句的一系列应用,当设置了标志之后,可以跳到所在函数内部的标号上。然而,本地跳转不能将控制权转移到所在程序的任意地点,不能跨越函数,因此也就有了非本地跳转

 1.非本地跳转是C语言提供的一种用户级的异常控制流的形式,它将控制直接从一个函数转移到另一个当前正在执行的函数,而不需要经过正常的调用-返回序列。

   非本地跳转是通过setjmp和longjmp函数提供的。

 我们来看看函数:

1 #include <setjmp.h>
2 //setjmp函数在env缓冲区中保存当前调用环境,以供后面的longjmp使用
3 int setjmp(jmp_buf env);
4 int sigsetjmp(sigjmp_buf env,int savesigs);
5 //sigsetjmp函数和siglongjmp函数是setjmp和longjmp的可以被信号处理程序使用的版本
6 //longjmp函数从env缓冲区中恢复调用环境,然后触发一个最近一次初始化env的setjmp调用的返回,然后setjmp返回,并带有非零的返回值retval
7 void longjmp(jmp_buf env,int retval);
8 void siglongjmp(sigjmp_buf env,int retval);
 返回值:若直接调用则返回0,若从siglongjmp调用返回则返回非0值

   要注意一点,setjmp的返回值不能被赋值给变量。但是可以用在switch语句或者条件语句的测试中

   setjmp函数只调用一次,但是返回多次,一次是当第一次调用setjmp,而调用环境保存在缓冲区env中时,一次是为每个相应的longjmp调用。

   longjmp函数被调用一次但从不返回。

 

     2.应用

  2.1非本地跳转允许从一个深层嵌套的函数调用中立即返回,通常由检测到某个错误引起的。

  示例代码:

  

 1 #include "csapp.h"
 2  
 3 jmp_buf buf;
 4  
 5 int error1 = 0; 
 6 int error2 = 1;
 7  
 8 void foo(void), bar(void);
 9  
10 int main() 
11 {
12     int rc;
13  
14     rc = setjmp(buf);
15     if (rc == 0)
16     foo();
17     else if (rc == 1) 
18     printf("Detected an error1 condition in foo\n");
19     else if (rc == 2) 
20     printf("Detected an error2 condition in foo\n");
21     else
22     printf("Unknown error condition in foo\n");
23     exit(0);
24 }
25  
26 /* deeply nested function foo */
27 void foo(void) 
28 {
29     if (error1)
30     longjmp(buf, 1); 
31     bar();
32 }
33  
34 void bar(void) 
35 {
36     if (error2)
37     longjmp(buf, 2); 
38 }

  2.2使信号处理程序分支到一个特殊的代码位置,而不是返回到被信号到达中断了的指令位置

  示例代码:

  这个代码挺有意思

 1 #include "csapp.h"
 2  
 3 sigjmp_buf buf;
 4  
 5 void handler(int sig) 
 6 {
 7     siglongjmp(buf, 1);
 8 }
 9  
10 int main() 
11 {
12     Signal(SIGINT, handler);
13  
14     if (!sigsetjmp(buf, 1)) 
15 /*The initial call to the sigsetjmp function saves the stack and signal context when the program first starts.*/
16     printf("starting\n");
17     else
18     printf("restarting\n");
19  
20     while(1) {
21     Sleep(1);
22     printf("processing...\n");
23     }
24     exit(0);
25 }

 

posted @ 2018-10-14 09:18  DXYE  阅读(769)  评论(0编辑  收藏  举报