setjump 和 longjump

简介: goto语句可以用于同一个函数内异常处理,不幸的是,goto是本地的,它只能跳到所在函数内部的标号上。为了解决这个限制,C函数库提供了setjmp()和longjmp()函数,它们分别承担非局部标号和goto作用。

goto语句可以用于同一个函数内异常处理,不幸的是,goto是本地的,它只能跳到所在函数内部的标号上。为了解决这个限制,C函数库提供了setjmp()和longjmp()函数,它们分别承担非局部标号和goto作用。头文件<setjmp.h>申明了这些函数及同时所需的jmp_buf数据类型。
    1.setjmp(jbuf)设置“jump”点,用正确的程序上下文填充jmp_buf对象jbuf。这个上下文包括程序存放位置、栈和框架指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp()返回0值。
    2. 以后调用longjmp(jbuf,r)的效果就是一个非局部的goto或“长跳转”到由jbuf描述的上下文处(也就是到那原来设置jbuf的setjmp()处)。当作为长跳转的目标而被调用时,setjmp()返回r (或1,如果r设为0的话)。(setjmp()不能在这种情况时返回0,否则就和设置jump点的返回值冲突了)

[cpp]  view plain copy
 
  1. #include "apue.h"  
  2. #include <setjmp.h>  
  3.   
  4. #define TOK_ADD    5  
  5.   
  6. jmp_buf jmpbuffer;  
  7.   
  8. int  
  9. main(void)  
  10. {  
  11.      char    line[MAXLINE];  
  12.   
  13.      if (setjmp(jmpbuffer) != 0)  
  14.          printf("error");  
  15.      while (fgets(line, MAXLINE, stdin) != NULL)  
  16.         do_line(line);  
  17.      exit(0);  
  18. }  
  19.   
  20.  ...  
  21.   
  22. void  
  23. cmd_add(void)  
  24. {  
  25.     int     token;  
  26.   
  27.     token = get_token();  
  28.     if (token < 0)    /* an error has occurred */  
  29.         longjmp(jmpbuffer, 1);  
  30.     /* rest of processing for this command */  
  31. }  


setjump和longjump返回时对auto变量、register变量、volatile变量和静态变量的恢复情况示例。cc -O选项表示编译优化。
longjump返回时一般情况下不会恢复到setjump时的值,此种情况属于未定义。
如果你不想让anto变量的值回滚,需要加上volatile属性。

[cpp]  view plain copy
 
  1. #include "apue.h"  
  2. #include <setjmp.h>  
  3.   
  4. static void f1(int, int, int, int);  
  5. static void f2(void);  
  6.   
  7. static jmp_buf jmpbuffer;  
  8. static int     globval;  
  9.   
  10. int  
  11. main(void)  
  12. {  
  13.      int             autoval;  
  14.      register int    regival;  
  15.      volatile int    volaval;  
  16.      static int      statval;  
  17.   
  18.      globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5;  
  19.   
  20.      if (setjmp(jmpbuffer) != 0) {  
  21.          printf("after longjmp:\n");  
  22.          printf("globval = %d, autoval = %d, regival = %d,"  
  23.              " volaval = %d, statval = %d\n",  
  24.              globval, autoval, regival, volaval, statval);  
  25.          exit(0);  
  26.      }  
  27.   
  28.      /* 
  29.       * Change variables after setjmp, but before longjmp. 
  30.       */  
  31.      globval = 95; autoval = 96; regival = 97; volaval = 98;  
  32.      statval = 99;  
  33.   
  34.      f1(autoval, regival, volaval, statval); /* never returns */  
  35.      exit(0);  
  36. }  
  37.   
  38. static void  
  39. f1(int i, int j, int k, int l)  
  40. {  
  41.     printf("in f1():\n");  
  42.     printf("globval = %d, autoval = %d, regival = %d,"  
  43.         " volaval = %d, statval = %d\n", globval, i, j, k, l);  
  44.     f2();  
  45. }  
  46. static void  
  47. f2(void)  
  48. {  
  49.     longjmp(jmpbuffer, 1);  
  50. }  
[cpp]  view plain copy
 
    1. $ cc testjmp.c               compile without any optimization  
    2. $ ./a.out  
    3. in f1():  
    4. globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99  
    5. after longjmp:  
    6. globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99  
    7. $ cc -O testjmp.c            compile with full optimization  
    8. $ ./a.out  
    9. in f1():  
    10. globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99  
    11. after longjmp:  
    12. globval = 95, autoval = 2, regival = 3, volaval = 98, statval = 99  
目录
相关文章
|
消息中间件 缓存 NoSQL
Redis经典问题:缓存雪崩
本文介绍了Redis缓存雪崩问题及其解决方案。缓存雪崩是指大量缓存同一时间失效,导致请求涌入数据库,可能造成系统崩溃。解决方法包括:1) 使用Redis主从复制和哨兵机制提高高可用性;2) 结合本地ehcache缓存和Hystrix限流降级策略;3) 设置随机过期时间避免同一时刻大量缓存失效;4) 使用缓存标记策略,在标记失效时更新数据缓存;5) 实施多级缓存策略,如一级缓存失效时由二级缓存更新;6) 通过第三方插件如RocketMQ自动更新缓存。这些策略有助于保障系统的稳定运行。
1030 1
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch 中的动态图与静态图:理解它们的区别及其应用场景
【8月更文第29天】深度学习框架中的计算图是构建和训练神经网络的基础。PyTorch 支持两种类型的计算图:动态图和静态图。本文旨在阐述这两种计算图的区别、各自的优缺点以及它们在不同场景下的应用。
2793 0
|
11月前
|
存储 数据安全/隐私保护 索引
SV39多级页表的硬件机制
【10月更文挑战第26天】SV39多级页表机制包括三级页表结构,每个页表项64位,通过SATP寄存器控制地址转换。地址转换过程涉及三级页表查找,最终生成物理地址。页表项包含有效位和访问权限位等标志,用于内存管理和访问控制。物理页帧的分配和回收确保内存的有效利用。
365 4
crash —— 查看内核配置
crash —— 查看内核配置
|
数据安全/隐私保护 Python
【Python】已解决:WARNING: Ignoring invalid distribution -addlepaddle (d:\soft\python36\lib\site-packages)
【Python】已解决:WARNING: Ignoring invalid distribution -addlepaddle (d:\soft\python36\lib\site-packages)
2987 1
|
Java 关系型数据库 MySQL
班级通讯录管理系统(Java+MySQL)
构建了一个Java Swing应用,搭配MySQL,实现班级通讯录管理。系统具备管理员登录、班级与学生信息的增删改查功能,每个班级窗口独立且自适应布局。利用GBK编码处理中文,JDBC连接数据库,优化窗口复用和代码结构,数据变更实时同步。示例截图展示详细界面。
班级通讯录管理系统(Java+MySQL)
|
存储 NoSQL 关系型数据库
【实战】在redis中怎样使用hash 实现类表结构存储数据
redis 中如何存储数据 如何实现类Mysql 式的表结构 具体实现方式。 详述
258 0
Raptor实践参考:斐波那契数列
返回-&gt;课程主页 2-7 斐波那契数列   输入整数n,输出斐波那契数列中的前n个数。斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……这个数列前两项均为1,从第3项开始,每一项都等于前两项之和。 【参考解答】 $(function ()
3975 0
NR PRACH(三)时域位置
由l0、N_RA_slot、N_RA_t和N_RA_dur,UE可以计算出所有RACH时机的起始符号l,公式为l = l0 + n_RA_t x N_RA_dur + 14 x n_RA_slot。其中的参数由table 6.3.3.2-2~4 得到,计算即可确定start symbol的位置,既然都这么说了,表中的starting symbol l0 肯定不是起始符号的索引,我最初犯的就是这个错误。
|
关系型数据库 MySQL 数据库
mysql 数据库中出现no database selected
mysql 数据库中出现no database selected
1804 1