setjmp和longjmp是C语言独有的,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,按照程序员的预先设计的意图,去实现对程序中可能出现的异常进行集中处理。
setjmp和longjmp的函数原型在setjmp.h中
函数原型:
int setjmp(jmp_buf envbuf);setjmp函数用缓冲区envbuf保存系统堆栈的内容,以便后续的longjmp函数使用。setjmp函数初次启用时返回0值。
void longjmp(jmp_buf envbuf, int val);longjmp函数中的参数envbuf是由setjmp函数所保存的堆栈环境,参数val设置setjmp函数的返回值。longjmp函数本身是没有返回值的,它执行后跳转到保存envbuf参数的setjmp函数调用,并由setjmp函数调用返回,此时setjmp函数的返回值就是val。
jmp_buf 记录了栈、指令位置等信息:
1,如果有多个setjmp 使用同一个jmp_buf, 那么longjmp会跳转到最近的setjmp位置:
#include "apue.h"#includestatic void f1(int, int, int, int);static void f2(void);static jmp_buf jmpbuffer;static int globval;intmain(void){ int autoval; register int regival; volatile int volaval; static int statval; globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5; if (setjmp(jmpbuffer) != 0) { printf("in main,after longjmp:\n"); printf("globval = %d, autoval = %d, regival = %d," " volaval = %d, statval = %d\n", globval, autoval, regival, volaval, statval); exit(0); } /* * Change variables after setjmp, but before longjmp. */ globval = 95; autoval = 96; regival = 97; volaval = 98; statval = 99; f1(autoval, regival, volaval, statval); /* never returns */ exit(0);}static voidf1(int i, int j, int k, int l){ printf("in f1():\n"); printf("globval = %d, autoval = %d, regival = %d," " volaval = %d, statval = %d\n", globval, i, j, k, l); if(setjmp(jmpbuffer) != 0){ printf("in f1, after longjmp!"); //longjmp(jmpbuffer,2); exit(0); } f2();}static voidf2(void){ printf("in f2"); longjmp(jmpbuffer, 1);}
2, 下面的使用方式会形成死循环:
if( setjmp(jmpbuffer) != 0 ){ printf("in f1, after longjmp!"); longjmp(jmpbuffer,2); exit(0);}
3, 如果想实现多个不同的跳转,可以使用多个jmp_buf :
#include "apue.h"#includestatic void f1(int, int, int, int);static void f2(void);static jmp_buf jmpbuffer;static jmp_buf jmpbuffer2;static int globval;intmain(void){ int autoval; register int regival; volatile int volaval; static int statval; globval = 1; autoval = 2; regival = 3; volaval = 4; statval = 5; if (setjmp(jmpbuffer2) == 2) { printf("\n in main,after longjmp:\n"); printf("globval = %d, autoval = %d, regival = %d," " volaval = %d, statval = %d\n", globval, autoval, regival, volaval, statval); exit(0); } /* * Change variables after setjmp, but before longjmp. */ globval = 95; autoval = 96; regival = 97; volaval = 98; statval = 99; f1(autoval, regival, volaval, statval); /* never returns */ exit(0);}static voidf1(int i, int j, int k, int l){ printf("in f1():\n"); printf("globval = %d, autoval = %d, regival = %d," " volaval = %d, statval = %d\n", globval, i, j, k, l); if(setjmp(jmpbuffer) != 0){ printf("in f1, after longjmp!\n"); longjmp(jmpbuffer2,2); exit(0); } f2();}static voidf2(void){ printf("in f2\n"); longjmp(jmpbuffer, 1);}
相应的输出:
in f1():globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99in f2in f1, after longjmp! in main,after longjmp:globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99