非本地跳转之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 ...
随机推荐
- P1220 关路灯
#include <bits/stdc++.h> using namespace std; int d[100], w[100], s, n; int dp[100][100][3]; i ...
- 关于flex中正则表达式上下文匹配的问题
按照课本与网上的说法,斜杠'/'表示匹配上下文,例如ab/cd表示当ab后面有cd时匹配ab 然而如果实际这么写,flex在调用该正则表达式时触发'unrecognized rule' flex源代码 ...
- couldn't find setter for xxxxx
springmvc hibernate框架,在执行普通的插入操作时报错,仔细检查实体类文件,确认该属性的getter setter方法都是有的,哭哭(´;︵;`)jpa策略生成的当然有.可是老是报这个 ...
- springmvc配置多视图 - tiles, velocity, freeMarker, jsp
转自: http://www.cnblogs.com/shanheyongmu/p/5684595.html <!-- Velocity --> <bean id="vel ...
- Sublime Text 2 JS 格式化插件 JsFormat的配置使用
(转自http://www.jb51.net/softjc/178401.html) 这里下载这插件包 https://github.com/jdc0589/JsFormat ,点油下角的zip就能下 ...
- 使用JCIFS获取远程共享文件
package com.jadyer.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOExc ...
- 同步github上fork出来的分支
1,clone自己的账号里fork库的分支到本地 git clone 地址_branch 2,增加远程原始分支 git remote add upstream 地址_master 3,fetch原始源 ...
- Android Bitmap转换WebPng图片导致损坏的分析及解决方案
出现问题的code!!! private void saveImage(String uri, String savePath) throws IOException { // 创建连接 HttpUR ...
- 【皇甫】☀初识AOP
新知识,新起点,下面介绍一下aop所要准备架包和各个层 特点: 创建好的各个层: 所需架包: 具体步骤: No.1 搭建分层架构 entity 1 public class User impleme ...
- java选择排序
/** * 选择排序 * @param a * @date 2016-10-8 * @author shaobn */ public static void selectSort(int[] a){ ...