17、深入理解计算机系统笔记:非本地跳转
1、C提供了用户级异常控制流,称为非本地跳转(nonlocal jump),它将控制流从一个函数转移到另一个当前正在执行的函数;而不需要经过正常的调用-返回序列。通过setjmp和longjmp来实现的。
函数原形
#include <setjmp.h> int setjmp(jmp buf env); int sigsetjmp(sigjmp buf env, int savesigs); //信号版本 returns: 0 from setjmp, nonzero from longjmps) #include <setjmp.h> void longjmp(jmp buf env, int retval); void siglongjmp(sigjmp buf env, int retval); //信号版本 never returns)
C++提供的异常机制是高层次的,是C的setjmp,longjmp函数的更加结构化的版本。可把try语句中的catch子句看作是setjmp函数的类似物;throw语句类似于longjmp函数。
The setjmp function saves the current stack context in the env buffer, for later
use by longjmp。The longjmp function restores the stack context from the env buffer
and then triggers a return from the most recent setjmp call that initialized env. The
setjmp then returns with the nonzero return value retval.
The setjmp function is called once but returns multiple times: once when the
setjmp is first called and the stack context is stored in the env buffer, and once for
each corresponding longjmp call. On the other hand, the longjmp function is called
once but never returns。
2、应用
1)允许从一个深层嵌套的函数调用中立即返回,通常是由检测到错误引起的。
示例代码
/* $begin setjmp */ #include "csapp.h" jmp_buf buf; int error1 = 0; int error2 = 1; void foo(void), bar(void); int main() { int rc; rc = setjmp(buf); /*The main routine first calls setjmp to save the current stack context*/ if (rc == 0) foo(); else if (rc == 1) printf("Detected an error1 condition in foo\n"); else if (rc == 2) printf("Detected an error2 condition in foo\n"); else printf("Unknown error condition in foo\n"); exit(0); } /* deeply nested function foo */ void foo(void) { if (error1) longjmp(buf, 1); bar(); } void bar(void) { if (error2) longjmp(buf, 2); } /* $end setjmp */
2)使一个信号处理程序分支到一个特殊的代码位置,而不是返回到被信号到达中断了的位置。
示例代码
/* $begin restart */ #include "csapp.h" sigjmp_buf buf; void handler(int sig) { siglongjmp(buf, 1); } int main() { Signal(SIGINT, handler); if (!sigsetjmp(buf, 1)) /*The initial call to the sigsetjmp function saves the stack and signal context when the program first starts.*/ printf("starting\n"); else printf("restarting\n"); while(1) { Sleep(1); printf("processing...\n"); } exit(0); } /* $end restart */ /*The program uses signals and nonlocal jumps to do a soft restart whenever the user types ctrl-c at the keyboard.当捕获到SIGINT信号时,不是从信号处理程序返回到被中断的处理循环,而是跳转到the beginning of the main program.*/
<Computer Systems:A Programmer's Perspective>