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. libpcap使用

    libpcap是一个网络数据包捕获函数库,功能非常强大,Linux下著名的tcpdump就是以它为基础的.今天我们利用它来完成一个我们自己的网络嗅探器(sniffer) 首先先介绍一下本次实验的环境: ...

  2. js中offsetHeight、clientHeight、scrollHeight等相关属性区分总结

    今天再次遇到了offset***.client***.scroll***的这三类属性的问题,总是混淆,现归纳总结如下: 大体上来说可以这样理解: client***属性(clientWidth.cli ...

  3. 升级 node 版本

    npm install -g n n stablen v0.10.26 n 0.10.26

  4. mac 终端常见指令

    基本命令 1.列出文件 ls 参数 目录名        例: 看看驱动目录下有什么:ls /System/Library/Extensions参数 -w 显示中文,-l 详细信息, -a 包括隐藏文 ...

  5. MyTask3

    近日做这个项目的时候感觉比较棘手的还是各类chart图处理的问题,详细的我就不多说了,代码我会贴出来,大家可以参考下,注释我还是写的比较详细的 1.饼状图百分比绑定问题(纠结了很久) // // ch ...

  6. ToString格式.

    C 货币 2.5.ToString("C") ¥2.50 D 十进制数 25.ToString("D5") 00025 E 科学型 25000.ToString ...

  7. wsdlLocation可以写成项目的相对路劲吗

    如果客户端的代码使用wsdl生成的话,这个地址是从wsdl描述的<service>里的<location>获取的,如果开发过程中服务地址换了,那只能手工来修改了,好像只有一个地 ...

  8. iOS如何准确获取通知

    iOS获取通知需要注意以下三个地方iOS 设备收到一条推送(APNs),用户点击推送通知打开应用时,应用程序根据状态不同进行处理需在 AppDelegate 中的以下两个方法中添加代码以获取apn内容 ...

  9. csv文本编辑引号问题

    今天发现一个csv的一个问题,csv工具类对于引号默认有特殊的处理.我希望写出来的结果是 1,"1",1 原来的代码是 CsvWriter cw=new CsvWriter(&qu ...

  10. OSG 安装配置

    对于普通用户推荐直接下载安装包配置.如有特殊需求或想了解编译过程可参考网上文章自己编译后配置.(通常建议使用第一种方法即可) 本人安装经验: 失败:自己系统64位,VS2010 32位,开始自己动手编 ...