C语言中有一个goto语句,其可以结合标号实现函数内部的任意跳转(通常情况下,很多人都建议不要使用goto语句,因为采用goto语句后,代码维护工作量加大)。另外,C语言标准中还提供一种非局部跳转“no-local goto",其通过标准库<setjmp.h>中的两个标准函数setjmp和longjmp来实现。

C标准库<setjmp.h>

下面是K&R的《C程序设计语言(第2版 . 新版)》第232页给出的关于标准库<setjmp.h>的说明。

非局部跳转<setjmp.h>

头文件<setjmp.h>中的说明提供了一种避免通常的函数调用和返回顺序的途径,特别的,它允许立即从一个多层嵌套的函数调用中返回。

8.1 setjmp

#include <setjmp.h>
int setjmp(jmp_buf env); setjmp()宏把当前状态信息保存到env中,供以后longjmp()恢复状态信息时使用。如果是直接调用setjmp(),那么返回值为0;如果是由于调用longjmp()而调用setjmp(),那么返回值非0。setjmp()只能在某些特定情况下调用,如在if语句、 switch语句及循环语句的条件测试部分以及一些简单的关系表达式中。 8.2 longjmp #include <setjmp.h>
void longjmp(jmp_buf env, int val); longjmp()用于恢复由最近一次调用setjmp()时保存到env的状态信息。当它执行完时,程序就象setjmp()刚刚执行完并返回非0值val那样继续执行。包含setjmp()宏调用的函数一定不能已经终止。所有可访问的对象的值都与调用longjmp()时相同,唯一的例外是,那些调用setjmp()宏的函数中的非volatile自动变量如果在调用setjmp()后有了改变,那么就变成未定义的。

cplusplus:

int setjmp (jmp_buf env);
Save calling environment for long jump

This macro with functional form fills env with information about the current state of the calling environment in that point of code execution, so that it can be restored by a later call to longjmp.

Calling longjmp with the information stored in env restores this same state and returns the control to that same point (the call to setjmp), which is evaluated as a particular non-zero value.

The state of the calling environment includes the values of all accessible objects, except those of automatic duration local to the function which do not have volatile-qualified types and which change before the call tolongjmp; these have indeterminate values.

The invocation of setjmp shall be an expression statement by itself, or be evaluated in a selection or iteration statement either as the (potentially negated) entire controlling expression or compared against an integer constant expression. Otherwise, it causes undefined behavior.

Parameters

env
Object of type jmp_buf where the environment information is stored.

Return Value

This macro may return more than once: A first time, on its direct invocation; In this case it always returns zero.
When longjmp is called with the information set to env, the macro returns again; this time it returns the value passed to longjmp as second argument if this is different from zero, or 1 if it is zero.

void longjmp (jmp_buf env, int val);
Long jump

Restores the environment to the state indicated by env, evaluating the setjmp expression that filled env as val.

The function never returns to the point where it has been invoked. Instead, the function transfers the control to the point where setjmp was last used to fill the env, and evaluates the whole expression as val (unless this is zero, in which case it evaluates as value of 1).

If env was not filled by a previous call to setjmp or if the function with such call has terminated execution, it causesundefined behavior.

In C++, the implementation may perform stack unwinding that destroys objects with automatic duration. If this invokes any non-trivial destructors, it causes undefined behavior.

Parameters

env
Object of type jmp_buf filled by a previous call to setjmp that contains information to restore the environment to that point.
val
Value to which the setjmp expression evaluates.
If this is zero, the expression evaluates as 1.
/* setjmp example: error handling */
#include <stdio.h> /* printf, scanf */
#include <stdlib.h> /* exit */
#include <setjmp.h> /* jmp_buf, setjmp, longjmp */ main()
{
jmp_buf env;
int val; val = setjmp (env);
if (val) {
fprintf (stderr,"Error %d happened",val);
exit (val);
} /* code here */ longjmp (env,); /* signaling an error */ return ;
}

The function uses setjmp to set up a catch-point that can later be called by longjmp to signal errors.

Output:

 

error 101 happended

setjmp.hC标准函数库中提供“非本地跳转”的头文件控制流偏离了通常的子程序调用与返回串行。互补的两个函数setjmp与longjmp提供了这种功能。

setjmp/longjmp的典型用途是异常处理机制的实现:利用longjmp恢复程序或线程的状态,甚至可以跳过栈中多层的函数调用。

setjmp保存当前的环境(即程序的状态)到平台相关的一个数据结构 (jmp_buf),该数据结构在随后程序执行的某一点可被 longjmp用于恢复程序的状态到setjmp调用所保存到jmp_buf时的原样。这一过程可以认为是"跳转"回setjmp所保存的程序执行状态。setjmp的返回值指出控制是正常到达该点还是通过调用longjmp恢复到该点。因此有编程的惯用法:

if( setjmp(x) ){/* handle longjmp(x) */}

#include <stdio.h>
#include <setjmp.h> static jmp_buf buf; void second(void) {
printf("second\n"); // 打印
longjmp(buf,); // 跳回setjmp的调用处 - 使得setjmp返回值为1
} void first(void) {
second();
printf("first\n"); // 不可能执行到此行
} int main() {
if ( ! setjmp(buf) ) {
first(); // 进入此行前,setjmp返回0
} else { // 当longjmp跳转回,setjmp返回1,因此进入此行
printf("main\n"); // 打印
} return ;
}

上述程序将输出:

second
main

注意到虽然first()子程序被调用,"first"不可能被打印。"main"被打印,因为条件语句if ( ! setjmp(buf) )被执行第二次。

更多:

http://zh.wikipedia.org/wiki/Setjmp.h

http://blog.codingnow.com/2010/05/setjmp.html

setjmp/longjmp 使用的更多相关文章

  1. Linux setjmp longjmp

    /********************************************************************* * Linux setjmp longjmp * 说明: ...

  2. 函数 setjmp, longjmp, sigsetjmp, siglongjmp

    一,相关函数接口 1,setjmp,longjmp,sigsetjmp,siglongjmp   #include <setjmp.h> int setjmp(jmp_buf env); ...

  3. setjmp/longjmp

    1.setjmp/longjmp属于传统的错误处理 2.setjmp/longjmp是对goto语句的补充,goto仅仅能实现局部跳转.setjmp/longjmp能够实现全局跳转 3.setjmp/ ...

  4. c setjmp longjmp

    http://coolshell.cn/?s=setjmp http://www.cnblogs.com/hazir/p/c_setjmp_longjmp.html double divide(dou ...

  5. goto语句的升级版,setjmp,longjmp

    我们知道goto语句是不能跳过函数的,但是在我么C语言的应用中,在不使用汇编的情况下,遇到需要跳出深层循环比如检错机制的时候,有确实想要跨函数跳转,有没有上面办法可以做到呢? 这就是今天要讲的两个库函 ...

  6. 信号处理函数的返回setjmp/longjmp

    信号处理函数可以正常返回,也可以调用其他函数返回到程序的主函数中,而不是从该处理程序返回. 正如ANSI C标准所说明的,一个信号处理程序可以返回或者调用abort.exit或longjmp(goto ...

  7. setjmp/longjmp 处理异常

    #include <stdio.h> #include <stdlib.h> #include <setjmp.h> jmp_buf jb; void f1() { ...

  8. setjmp()/longjmp()的使用方法

    setjmp和longjmp.为了让你实现复杂的流控制,程序在系统里面运行完全依靠内存(代码段,全局段,堆存储器,栈存储器)和寄存器的内容(栈指针,基地址,计数器),setjmp保存当前的寄存器里面的 ...

  9. 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 ...

随机推荐

  1. android 40 Io编程

    Io编程:内存卡和sd卡.字符串存入内存卡然后读出来. activity: package com.sxt.day06_06; import java.io.FileInputStream; impo ...

  2. iOS--inputView和inputAccessoryView

    iOS–inputView和inputAccessoryView 什么是inputView和inputAccessoryView? 如果是UITextField和UITextView,下面是声明文件源 ...

  3. 关于ADO.NET的一些知识整理

    ADO.NET是什么 虽然我们都知道ADO.NET是对数据库的操作,但是要真的说出ADO.NET的具体含义还不是很容易. ADO.NET是ActiveX Data Objects的缩写,它是一个COM ...

  4. ASP.NET MVC 第三回 Controller与View

    这节我们让ASP.NET MVC真正的跑起来 一.新建Controller 首先我们自己新建一个新的Controller在Controllers上点右键,添加,Controller选项   之后出现一 ...

  5. http学习笔记一

  6. java 反射调用支付SDK

    在android开发中会遇到各种SDK的接入,很是麻烦.最初在想能不能把所有的SDK都 融合到一个当中,发现有点异想天开.但是也可以解决SDK资源不小心没有引入,导致程序调用接口崩溃问题.经过查资料, ...

  7. .NET Core跨平台开发

    对于.NET开源计划想必关注的人已经跃跃欲试了,但是真正将其用于开发的目前来说不多.毕竟截至本文发布时.NET Core才发布到1.0RC2版本.正式版预计还有一段时间.况且大多数人都是持观望态度,就 ...

  8. 转载[POJ题型分类]

    北大ACM题分类 主流算法: 1.搜索 //回溯 2.DP(动态规划) 3.贪心 4.图论 //Dijkstra.最小生成树.网络流 5.数论 //解模线性方程 6.计算几何 //凸壳.同等安置矩形的 ...

  9. [转]Mysql导入导出工具Mysqldump和Source命令用法详解

    Mysql本身提供了命令行导出工具Mysqldump和Mysql Source导入命令进行SQL数据导入导出工作,通过Mysql命令行导出工具Mysqldump命令能够将Mysql数据导出为文本格式( ...

  10. 输出内容(document.write)

    document.write() 直接在页面中输出内容 第一种 直接输出 document.write("I Love Javascript !") //输出内容为:I Love ...