• 二十、Linux 进程与信号---非局部跳转


    20.1 setjmp 和 longjmp 函数

    20.1.1 函数介绍

    #include <setjmp.h>
    int setjmp(jmp_buf env);
    • 函数功能:设置非局部跳转的跳转点(设置跳转点)
    • 返回值:直接调用返回0,若从 longjmp 调用返回则返回0
    • 这个函数会被执行两次,一次是自己本身使用的时候返回0,另一次再调用 longjump 的时候,此函数再返回 longjmp 中的 val 值
    #include <setjmp.h>
    void longjmp(jmp_buf env, int val);
    • 函数功能:进行非局部跳转,val 为返回值(具体完成跳转,例如goto)
    • 参数:
      • @env:
        • 一个特殊类型 jmp_buf。这一数据类型是某种形式的数组,其中存放在调用 longjmp 时能用来恢复栈状态的所有信息。一般,env 变量是个全局变量,因为需从另一个函数中引用他。
    • C程序缺乏异常处理的语法,可使用非局部跳转处理C程序的异常
    • goto语句仅限于函数内部的跳转,而 longjmp 不限于

    20.1.2 例子

      process_jmp.c

      1 #include <setjmp.h>
      2 #include <unistd.h>
      3 #include <string.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 
      7 #define TOK_ADD        5
      8 #define TOK_SUB        6
      9 
     10 void do_line(char *line);
     11 void cmd_add(void);
     12 void cmd_sub(void);
     13 int get_token(char *item);/* 获取分割字符 */
     14 
     15 char *prompt = "cal:"; /* 命令行提示符 */
     16 jmp_buf env;/* 跳转的 buf 结构 */
     17 
     18 int main(void)
     19 {
     20     ssize_t size = strlen(prompt) * sizeof(char);
     21     char buff[256];
     22     ssize_t len;
     23 
     24     /* 设置跳转点 */
     25     /* setjmp 第一次执行成功返回0,调用 longjmp 后此处再返回 非0值 */
     26     if(setjmp(env) < 0) {
     27         perror("setjmp error");
     28         exit(1);
     29     }
     30 
     31     write(STDOUT_FILENO, prompt, size);
     32     while(1) {
     33         len = read(STDIN_FILENO, buff, 256);
     34         if(len < 0)    break;
     35 
     36         buff[len - 1] = 0;
     37         do_line(buff);
     38         write(STDOUT_FILENO, prompt, size);
     39     }
     40 
     41     return 0;
     42 }
     43 
     44 void do_line(char *line)
     45 {
     46     int cmd = get_token(line);
     47 
     48     switch(cmd) {
     49         case TOK_ADD:
     50             cmd_add();
     51             break;
     52         case TOK_SUB:
     53             cmd_sub();
     54             break;
     55         default:
     56             fprintf(stderr, "error command
    ");
     57     }
     58 
     59 }
     60 
     61 void cmd_add(void)
     62 {
     63     int i = get_token(NULL);
     64     int j = get_token(NULL);
     65     printf("result is %d
    ", i + j);
     66 }
     67 
     68 void cmd_sub(void)
     69 {
     70     int i = get_token(NULL);
     71     int j = get_token(NULL);
     72     printf("result is %d
    ", i - j);
     73 }
     74 
     75 static int is_number(char *item)
     76 {
     77     int len = strlen(item);
     78     int i;
     79 
     80     for(i = 0; i < len; i++)
     81     {
     82         if(item[i] > '9' || item[i] < '0')
     83             return 0;
     84     }
     85 
     86     return 1;
     87 }
     88 
     89 int get_token(char *line)
     90 {
     91     /*
     92      * add 3 4
     93      */
     94     char *item = strtok(line, " ");
     95     
     96     if(line != NULL) {
     97         if(!strcmp("add", item))    return TOK_ADD;
     98         if(!strcmp("sub", item))    return TOK_SUB;
     99     } else {
    100         if(is_number(item)) {
    101             int i = atoi(item);
    102             return i;
    103         } else {
    104             fprintf(stderr, "arg not number
    ");
    105             /* 如果输入的参数不正常,则让程序跳回到主函数执行下一次循环 */
    106             /* 进行非局部跳转 */
    107             longjmp(env, 1);// 跳转到 setjmp 处执行
    108         }
    109     }
    110 }

      执行成功

      

      如果将红色部分注释掉,会发现打印 reasult is xx 数字,xx数字 是一个随机值,因为再 get_token 函数中,fprintf 后就没有做退出也没有做返回实际数字,那么函数运行完毕后,就会返回一个随机值来做加减运行,结果也就变为了一个随机值。

    20.2 非局部跳转中,变量的使用

      编译器优化编译后:

    • 全局变量、静态变量和 volatile(易矢变量)
      • 不能恢复到原始值
    • 寄存器变量
      • 可以恢复到原始值  
    • 自动变量潜在问题  
      • 优化编译后可能会恢复
    • malloc 变量
      • 与编译器优化有关,有的编译器进行优化编译会改变,有的编译器不会,具体看编译器优化    

      longjmp_val.c

     1 #include <setjmp.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <malloc.h>
     5 
     6 int g_val;
     7 
     8 jmp_buf env;
     9 
    10 /*
    11  * g_val:全局变量
    12  * s_val:静态变量
    13  * a_val:自动变量,即局部变量
    14  * r_val:寄存器变量
    15  * m_val:通过 malloc 分配的变量
    16  * v_val:易失变量
    17  */
    18 void fun1(int g_val, int s_val, int a_val, int r_val, int m_val, int v_val);
    19 
    20 void fun2();
    21 
    22 int main(void)
    23 {
    24     static int s_val;
    25     int a_val;
    26     register r_val;
    27     int *m_val = (int *)malloc(sizeof(int));
    28     volatile int v_val;
    29 
    30     g_val = 1;
    31     s_val = 2;
    32     a_val = 3;
    33     r_val = 4;
    34     *m_val = 5;
    35     v_val = 6;
    36 
    37     int k = 0;
    38 
    39     if((k = setjmp(env)) < 0) {
    40         perror("setjmp error");
    41         exit(1);
    42     } else if( k == 1) {
    43         printf("after longjmp
    ");
    44         printf("g_val %d, s_val %d, a_val %d r_val %d, m_val %d v_val %d
    ",
    45                 g_val, s_val, a_val, r_val, *m_val, v_val);
    46         exit(0);
    47     }
    48 
    49     g_val = 10;
    50     s_val = 20;
    51     a_val = 30;
    52     r_val = 40;
    53     *m_val = 50;
    54     v_val = 60;
    55 
    56     fun1(g_val, s_val, a_val, r_val, *m_val, v_val);
    57 
    58     return 0;
    59 }
    60 
    61 
    62 void fun1(int g_val, int s_val, int a_val, int r_val, int m_val, int v_val)
    63 {
    64     printf("before longjmp
    ");
    65 
    66     printf("g_val %d, s_val %d, a_val %d r_val %d, m_val %d v_val %d
    ",
    67             g_val, s_val, a_val, r_val, m_val, v_val);
    68 
    69     fun2();
    70 }
    71 
    72 void fun2()
    73 {
    74     longjmp(env, 1);
    75 }

      不进行优化编译后执行:

      

      

      优化编译后:

      

      

  • 相关阅读:
    celery 使用(一)
    RabbitMQ(一 初识)
    python 生成器与迭代器(yield 用法)
    python与consul 实现gRPC服务注册-发现
    python 使用gRPC
    IDEA 破解图文教程
    ArrayList 源码分析 -- 扩容问题及序列化问题
    面向对象来理解链表
    Winrar去广告图文教程
    Spring Boot 整合JDBC 实现后端项目开发
  • 原文地址:https://www.cnblogs.com/kele-dad/p/9126855.html
Copyright © 2020-2023  润新知