非本地跳转之setjmp与longjmp
非本地跳转(unlocal jump)是与本地跳转相对应的一个概念。
本地跳转主要指的是类似于goto语句的一系列应用,当设置了标志之后,可以跳到所在函数内部的标号上。然而,本地跳转不能将控制权转移到所在程序的任意地点,不能跨越函数,因此也就有了非本地跳转。
C语言里面提供了setjmp和longjmp函数来进行跨越函数之间的控制权的跳转,从而称之为非本地跳转。
#include <setjmp.h>
int setjmp(jmp_buf env);
该函数主要用来保存当前执行状态,作为后续跳转的目标。调用时,当前状态会被存放在env指向的结构中,env将被 long_jmp 操作作为参数,以返回调用点,跳转的结果看起来就好像刚从setjmp返回一样。
需要注意的是,第一次调用setjmp的时候返回值为0;而从long_jmp操作返回时,返回值是非0的,数值与longjmp传入的参数value有关。通过判断setjmp的返回值,就可以判断当前执行状态。
#include<setjmp.h>
void long_jmp(jmp_buf env, int value);
该函数用来恢复env中保存的执行状态,另一参数value用来传递返回值给跳转目标。如果value值为0,则跳转后返回setjmp处的值为1;否则,返回setjmp处的值为value。
因此,整个非本地跳转的执行过程是:首先,在程序中调用setjmp进行当前运行栈环境的保存,接着在程序的其它地方调用longjmp进行跳转,跳转回的位置就是该setjmp的位置。
这其中需要注意的是:jmp_buf类型的变量env,因为该变量保存的是当前执行位置的运行栈环境;因此如果需要还能跳转到这个位置,那么longjmp必须能调用到这个env变量,因此这个变量一般为全局的。
接下来,简单的介绍一下运行栈的概念。
运行栈
简单的来说,程序运行的时候如果一个函数Fa内部调用了另一个函数Fb,那么当Fb执行完了之后,控制权如何返回给Fa,并继续执行Fa后面的语句呢?这就使用到了运行栈。
简要的说,运行栈里按照函数调用的顺序将一个个函数压入栈中,当一个函数执行结束之后,这个函数的栈帧(stack frame)就会从运行栈中pop出来,并将控制权(PC)转向调用函数(callee),控制权的记录就在每个函数所对应的的栈帧中。
因此,如果我们有程序段如下:
void Fa()
{
...
Fb();
...
}
void Fb()
{
...
Fc();
...
}
void Fc()
{
...
//do something here
} void main()
{
...
Fa();
}
那么,当调用到函数Fc时程序的运行栈大致如下图所示:

当执行完Fc之后就会将Fc的栈帧pop出来,如下图所示:

非本地跳转模拟异常处理机制
当使用非本地跳转时,就不需要一层层的解开程序调用栈,而是直接将控制流转移到对应的位置。
在最初,还没有实现异常处理机制的时候,有的时候会用非本地跳转来模拟异常处理机制,大致思路如下:
#define myTry if(setjmp(env) == 0){
#define myCatch(err) }else if(err != NULL){ \
//TO DO SOMETHING HERE
\
}
#define myThrow(err) longjmp(env, err.ToInteger())
在myTry处设置setjmp,并保存当前的程序运行栈到env中,当程序中某个函数throw出一个异常时,就使用longjmp进行跳转。此时,程序又回到了setjmp处,但是因为返回值已经被设置为err.ToInteger(),因此setjmp的返回值肯定不是0,于是程序就进入到了else if分支,即myCatch语句块中。
但是,使用非本地跳转来模拟异常处理机制时会产生一定的问题,那就是在语句块中定义的局部变量所占的内存并不会被正常的释放,导致内存泄漏。
因为,非本地跳转在发生跳转时是直接将程序的控制流转移过去,而不是进行正常的栈退解(stack unwinding)操作,因此并不能识别出其中的变量并进行析构,不过现在的一些编译器已经实现了相应的功能,因编译器而异。
非本地跳转之setjmp与longjmp的更多相关文章
- 【转】浅析C语言的非局部跳转:setjmp和longjmp
转自 http://www.cnblogs.com/lienhua34/archive/2012/04/22/2464859.html C语言中有一个goto语句,其可以结合标号实现函数内部的任意跳转 ...
- Unix系统编程()执行非局部跳转:setjmp和longjmp
使用库函数setjmp和longjmp可执行非局部跳转(local goto). 术语"非局部(nonlocal)"是指跳转目标为当前执行函数之外的某个位置. C语言里面有个&qu ...
- (C)非局部跳转语句(setjmp和longjmp)
1. 特点 非goto语句在函数内实施跳转,而是在栈上跳过若干调用帧,返回到当前函数调用路径上的某一语句. 头文件包含#include Void longjmp(jmp_buf env,int val ...
- C语言中setjmp与longjmp学习笔记
C语言中setjmp与longjmp学习笔记 一.基础介绍 头文件:#include<setjmp.h> 原型: int setjmp(jmp_buf envbuf) ,然而longjm ...
- 【转载】setjmp和longjmp函数使用详解
[说明]本文上半部分转载自 wykwdy007 的转载文章 http://blog.csdn.net/wykwdy007/article/details/6535322 --------------- ...
- setjmp和longjmp函数使用详解
源地址:http://blog.csdn.net/zhuanshenweiliu/article/details/41961975 非局部跳转语句---setjmp和longjmp函数.非局部指的是, ...
- setjmp与longjmp非局部跳转函数的使用
[root@bogon code]# cat c.c #include<stdio.h> #include<setjmp.h> static jmp_buf env;//定义全 ...
- C和指针 第十六章 标准函数库 本地跳转setjmp.h
setjmp和longjmp提供一种类似goto语句的机制,但它的作用域不局限于同一个函数的作用域之内.这些函数可以用于深层次的嵌套函数调用链. int setjmp(jmp_buf state); ...
- setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto
目录 . 应用场景 . Use Case Code Analysis . 和setjmp.longjmp有关的glibc and eglibc 2.5, 2.7, 2.13 - Buffer Over ...
随机推荐
- could not get lock /var/lib/dpkg/lock
这个问题的原因可能是有另外一个程序正在运行,导致资源被锁不可用.而导致资源被锁的原因,可能是上次安装时没正常完成,而导致出现此状况. 解决方法:输入以下命令 sudo rm /var/cache/ap ...
- CSS中有关水平居中和垂直居中的解决办法
CCS中让div等块级元素在父级元素中居中的方法: (1)div{ margin:0 auto } 该方法只能实现水平的居中,无法实现元素的垂直居中 (2)当div元素的宽高是固定的,然后设置位 ...
- 上传图片插件鼠标手cursor:pointer;不生效
问题: 只在谷歌里失效; 解决: font-size:0; 参考: http://jingyan.baidu.com/article/48b558e32fabb67f38c09a81.html htt ...
- django--models操作
1.models的功能 操作数据库 提交验证 在django的admin中,使用的是modelForms所以在验证的时候,尽管在models后有error_ message参数也不会根据此来提示.具体 ...
- HTML中head里的内容经浏览器解析后全到body里了
HTML中head里的内容经浏览器解析后全到body里了 修改完代码后,用chrome审查元素,head里的内容都到body中去了 http://bbs.csdn.net/topics/3802586 ...
- C#类继承和接口继承时一些模棱两可的问题[转]
原文地址:http://www.cnblogs.com/harleyhu/archive/2012/11/29/2794809.html 1.在father定义的方法若含有virtual关键字,chi ...
- magento模板文件结构详解
来自: 南国佳木(茶者,南方之嘉木也.) 2015-09-01 23:14:43 模板文件主要分为xml布局文件和html文件 Layout(布局)文件夹存放的是此模板的.xml文件(也就是模版的结构 ...
- Android studio 出现 Unsupported major.minor version 52.0
参考资料:http://blog.csdn.net/fakine/article/details/51241202 最近更新了Android studio 之后,出现了Error:java.lang. ...
- express 的 app.get和app.use
1.若调用app.get()时只有一个参数,则认为是取设置值,否则认为是注册路由 2.所有被 app.use() 接收的 handle 会被放到一个 stack 里边 app.get() 执行的时候会 ...
- vulcan测试记录
感觉这个游戏很赞,是六个里面最喜欢的一个了 1.有时候挖坑对于位置要求比较大? 2.感觉难度比较大,尤其是玩到第三关很考验啊(不过从另一个方面来说也是优点?) 3.玩到现在对于怪物吃金子的原理没有很懂 ...