1、非本地跳转的作用
是C提供的一种用户级异常控制流的形式。它将控制直接从一个函数转移到另一个当前正在执行的函数, 而不需要经过正常的调用-返回序列
2、非本地跳转的实现
C中通过setjmp和longjmp函数来实现。
1. setjmp 函数
setjmp函数在env缓冲区中保存当前调用环境, 以供后面的longjmp使用, 并返回
0。调用环境包括程序计数器、栈指针和通用目的寄存器。
setjmp返回的值不能被赋值给变量,不过它可以安全地用在switch或条件语句的测试中
2. longjmp函数
longjmp函数从env缓冲区中恢复调用环境, 然后触发一个从最近一次初始化env
的setjmp调用的返回。然后setjmp返回, 并带有非零的返回值retval。
3. 二者关系与示例
setjmp函数只被调用一次, 但返回多次: 一次是当第一次调用setjmp, 而调用环境保存在缓冲区env中时,一次是为每个相应的longjmp调用。另一方面, longjmp函数被调用一次, 但从不返回。
第一次调用setjmp时返回0,调用foo,如果foo出现错误,longjmp会调用最近的setjmp,又回到switch语句中,bar中出错同理。
4. 问题
由于这样的跳转,可能某些本应该在结束时释放的资源会被跳过,造成内存泄漏。
3、应用
1. 允许从深层嵌套的函数调用中立即返回
是允许从一个深层嵌套的函数调用中立即返回, 通常是由检测到某个错误情况引起的。如果在一个深层嵌套的函数调用中发现了一个错误情况,我们可以使用非本地跳转直接返回到一个普通的本地化的错误处理程序, 而不是费力地解开调用栈
2. 使一个信号处理程序分支返回到特殊位置
使一个信号处理程序分支到一个特殊的代码位置, 而不是返回到被信号到达中断了的指令的位置。例子如下
操作结果是这样的
说明:
为了避免竞争, 必须在调用了sigsetjmp之后再设置处理程序。否则, 就会冒在初始调用sigsetjmp为siglongjmp设置调用环境之前运行处理程序的风险。也就是还没调用sigsetjmp的时候就按下Ctrl+C
4、C++与Java中的软件异常
C++和Java提供的异常机制是较高层次的, 是C语言的setjmp和longjmp函数
的更加结构化的版本。你可以把try语句中的catch子句看做类似于setjmp函数。相
似地, throw语句就类似于longjmp函数。