zoukankan      html  css  js  c++  java
  • 非本地跳转

       首先介绍下与非本地跳转的对应的本地跳转,本地跳转指的是类似于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
    ");
    19     else if (rc == 2) 
    20     printf("Detected an error2 condition in foo
    ");
    21     else
    22     printf("Unknown error condition in foo
    ");
    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
    ");
    17     else
    18     printf("restarting
    ");
    19  
    20     while(1) {
    21     Sleep(1);
    22     printf("processing...
    ");
    23     }
    24     exit(0);
    25 }
  • 相关阅读:
    centos8 将SSSD配置为使用LDAP并要求TLS身份验证
    Centos8 搭建 kafka2.8 .net5 简单使用kafka
    .net core 3.1 ActionFilter 拦截器 偶然 OnActionExecuting 中HttpContext.Session.Id 为空字符串 的问题
    Springboot根据不同环境加载对应的配置
    VMware Workstation12 安装 Centos8.3
    .net core json配置文件小结
    springboot mybatisplus createtime和updatetime自动填充
    .net core autofac依赖注入简洁版
    .Net Core 使用 redis 存储 session
    .Net Core 接入 RocketMQ
  • 原文地址:https://www.cnblogs.com/blzm742624643/p/9785146.html
Copyright © 2011-2022 走看看