非本地跳转之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 ...
随机推荐
- WPF重写Image实现动态图片--未测试
WPF很强大,但是当WPF的image控件遇到gif时就只读了图片的第一帧,很好很强大! WPF不屑于gif的简单动画! 幸好WPF里有MediaElement这个东西,它是对MediaPlyer的一 ...
- ArcGIS Server,rest路径输入要素json 格式描述
以下内容只测试了简单线, 在ArcGIS Server 的rest路径下可以对服务进行操作,如Query等,这些操作可以输入json 格式要素描述或运行得到即输出json格式要素描述. 如博客:htt ...
- C# EF增删改查
1.增 //1.创建一个EF数据上下文对象 MyDBEntities context=new MyDBEntities(); //2.将要添加的数据,封装成对象 Users user = new Us ...
- 微信支付开发(7) H5支付
关键字:微信支付 微信支付v3 H5支付 wap支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3_h5.html 本文 ...
- Hibernate操作指南-实体之间的关联关系(基于注解)
- Hibernate操作指南-搭建一个简单的示例(基于原生API和注解)
- jQuery工具函数(转)
原文地址:http://www.cnblogs.com/kissdodog/archive/2012/12/27/2835561.html 作者:逆心 ------------------------ ...
- IOS 支持HTTPS调用(AFNetWorking框架)
1.ATS开关开启2.manager.securityPolicy.allowInvalidCertificates = YES; manager.securityPolicy.validatesDo ...
- linux-----------shell的基础命令
shell中截取字符串的方法有很多中, ${expression}一共有9种使用方法. ${parameter:-word} ${parameter:=word} ${parameter:?word} ...
- hdu5714 拍照[2016百度之星复赛C题]
由于船移动的速度都一样,那么对于往一个方向的船相对距离其实是不变的,我们可以把往一个方向移动的船都视作静止,并求出在哪些观测位置可以看到,很明显对于船[x,y,z],当x+z>=y-z的时候,可 ...