博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
setjmp.h文件详解
阅读量:6581 次
发布时间:2019-06-24

本文共 4701 字,大约阅读时间需要 15 分钟。

hot3.png

setjmp.h

维基百科,自由的百科全书
  • <setjmp.h>
 •   •   • 

setjmp.h是中提供“非本地跳转”的:偏离了通常的子程序调用与返回序列。互补的两个函数setjmp与longjmp提供了这种功能。

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

目录

 
 [] 

[]成员函数

int setjmp(jmp_buf env) 建立本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序 保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返回,setjmp返回值为0。如果是从longjmp恢复的程序调用环境返回,setjmp返回非零值。
void longjmp(jmp_buf env, int value) 恢复env所指的缓冲区中的程序调用环境上下文,env所指缓冲区的内容是由setjmp子程序调用所保存。value的值从longjmp传递给setjmplongjmp完成后,程序从对应的setjmp调用处继续执行,如同setjmp调用刚刚完成。如果value传递给longjmp零值,setjmp的返回值为1;否则,setjmp的返回值为value

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

[]成员类型

jmp_buf 数组类型,例如struct int[16]struct __jmp_buf_tag,用于保存恢复调用环境所需的信息。

[]告诫与限制

longjmp实现了非本地跳转,微软的IA32程序设计环境中正常的"栈卷回"("stack unwinding")因而没有发生,所以诸如栈中已定义的局部变量的析构函数的调用(用于销毁该局部变量)都没有执行。所有依赖于栈卷回调用析构函数所做的扫尾工作,如关闭文件、释放堆内存块等都没有做。但在微软的X64程序设计环境,longjmp启动了正常的"栈卷回"。

如果setjmp所在的函数已经调用返回了,那么longjmp使用该处setjmp所填写的对应jmp_buf缓冲区将不再有效。这是因为longjmp所要返回的"栈帧"(stack frame)已经不再存在了,程序返回到一个不再存在的执行点,很可能覆盖或者弄坏程序栈.

[]使用例子

[]简单例子

#include 
#include
static jmp_buf buf; void second(void) {
printf("second\n"); // 打印 longjmp(buf,1); // 跳回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 0; }

上述程序将输出:

secondmain

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

[]异常处理

在下例中,setjmp被用于包住一个例外处理,类似。longjmp调用类似于throw语句,允许一个异常返回给setjmp一个异常值。下属代码示例遵从与:仅在特定范围内引用setjmp

  • ifswitch或它们的嵌套使用的条件表达式
  • 上述情况下与!一起使用或者与整数常值比较
  • 作为单独的语句(不使用其返回值)

遵从上述规则使得创建程序环境缓冲区更为容易。更一般的使用setjmp可能引起未定义的行为,如破坏局部变量;编译器被要求保护或警告这些用法。但轻微的复杂用法如switch ((exception_type = setjmp(env))) { }在文献与实践中是常见的,并保持了相当的可移植性。

#include 
#include
#include
#include
void first(void); void second(void); /* This program's output is: calling firstcalling secondentering secondsecond failed with type 3 exception; remapping to type 1.first failed, exception type 1 */ /* Use a file scoped static variable for the exception stack so we can access * it anywhere within this translation unit. */ static jmp_buf exception_env; static int exception_type; int main() {
void *volatile mem_buffer; mem_buffer = NULL; if (setjmp(exception_env)) {
/* if we get here there was an exception */ printf("first failed, exception type %d\n", exception_type); } else {
/* Run code that may signal failure via longjmp. */ printf("calling first\n"); first(); mem_buffer = malloc(300); /* allocate a resource */ printf(strcpy((char*) mem_buffer, "first succeeded!")); /* ... this will not happen */ } if (mem_buffer) free((void*) mem_buffer); /* carefully deallocate resource */ return 0; } void first(void) {
jmp_buf my_env; printf("calling second\n"); memcpy(my_env, exception_env, sizeof(jmp_buf)); switch (setjmp(exception_env)) {
case 3: /* if we get here there was an exception. */ printf("second failed with type 3 exception; remapping to type 1.\n"); exception_type = 1; default: /* fall through */ memcpy(exception_env, my_env, sizeof(jmp_buf)); /* restore exception stack */ longjmp(exception_env, exception_type); /* continue handling the exception */ case 0: /* normal, desired operation */ second(); printf("second succeeded\n"); /* not reached */ } memcpy(exception_env, my_env, sizeof(jmp_buf)); /* restore exception stack */ } void second(void) {
printf("entering second\n" ); /* reached */ exception_type = 3; longjmp(exception_env, exception_type); /* declare that the program has failed */ printf("leaving second\n"); /* not reached */ }

[]参考文献

  1. ^   ISO C标准要求setjmp必须是宏实现,但POSIX明确称未定义setjmp是宏实现还是函数实现。
  2.  Visual Studio 2008用法
  3.   2.7的用法
  4.  Microsoft Visual C++ 2010 x32或x64与Intel ICC 2011 (version 12) x32或x64,编译结果都是longjmp启动了正常的"栈卷回"。但GCC 4.4 x32版编译的longjmp不执行"栈卷回"。可见,是否“栈卷回”不具有移植性。
  5.  
  6.  

[]外部链接

转载于:https://my.oschina.net/wxwHome/blog/51311

你可能感兴趣的文章
thinkphp 3.2 增加每页显示条数
查看>>
oracle日常简单数据备份与还原
查看>>
我的友情链接
查看>>
黑马程序员__反射总结
查看>>
Scala学习笔记(5)-类和方法
查看>>
Quartz原理
查看>>
完全卸载oracle|oracle卸载|彻底卸载oracle
查看>>
垃圾收集基础
查看>>
Docker安装及基本命令
查看>>
控制namenode检查点发生的频率
查看>>
Linux存储挂载后,无法正常卸载的解决方法
查看>>
2、递归遍历文件夹下每一个文件
查看>>
Remove auto_increment from Schema Dumps (mysqld...
查看>>
解决activity加上Theme.Translucent.NoTitleBar 页面跳转显示桌面
查看>>
php类库
查看>>
浅谈Java中的对象和引用
查看>>
SQL 注入自我总结
查看>>
Linux线程
查看>>
Exchange Server 2013 系列八:邮箱服务器角色DAG实战
查看>>
一个有趣的命令
查看>>