主要看了思路,代码未测试。数组
1 /*yvals.h*/ 2 #define _YVALS_H_ 3 4 #define MYEDOM 33 5 #define MYERANGE 34 6 #define MYEFPOS 35 7 #define MYERRMAX 36 8 9 #define _ILONG 1 10 #define _CSIGN 1 11 #define _MBMAX 2 12 13 #define _JBFP 1 14 #define _JBMOV 60 15 #define _JBOFF 4 16 #define _NSETJMP 17 17 18 #define _SIGABRT 6 19 #define _SIGMAX 32
1 /*my_setjmp.h*/ 2 /* 3 * c程序不容许函数的嵌套定义。 4 * 因此除了返回调用哪一个函数的表达式外,c语言没有提供其余将控制权转移到一个函数以外的简单方法。 5 * c语言使用库函数实现非本地控制转移。 6 * jmp_buf类型,标量数据对象类型。 7 * longjmp函数,用来实现非本地控制转移。 8 * setjmp宏,把当前调用的上下文信息存储到一个jmp_buf类型的数据对象中,并在你想把控制权传递给相应的 9 * longjmp调用的地方作标记。 10 * 两个潜在危险:包含setjmp宏达表达式;在执行setjmp的函数中声明的动态存储空间。 11 * 12 * 通常电脑有必定数量的寄存器,在对表达式进行求值的时候,寄存器用来保存中间结果。 13 * 但在计算一个很是复杂的表达式时,这些寄存器可能不够用,这时用户就会迫使代码生成器把中间结果存储在动态存储空间中。 14 * c标准规定把包含setjmp的表达式做为子表达式使用。为了排除某些可能把中间结果存储在setjmp未知的动态存储空间中的表达式。 15 * 因此可编写switch(setjmp(buf)...,if(2<setjmp(buf))...if(!setjmp(buf))...setjmp(buf). 16 * 不能可靠把setjmp的值赋给其余的变量,如n=setjmp(buf).标准未定义。 17 * 18 * 宏setjmp的调用应该只出如今下面某个上下文环境中。 19 * 1,一个选择或者循环语句的整个控制表达式。 20 * 2,关系运算符或者等于运算符的其中一个操做数,另外一个操数是一个整值常量表达式,它的结果表达式是一个选择或循环语言的整个控制表达式。 21 * 3,一元操做符!的操做数,它的结果表达式是一个选择或循环语句的整个控制表达式。 22 * 4,是一个表达式语句(可能强制转换为void类型)的整个表达式。 23 * 函数longjmp使用相应的jmp_buf参数来恢复程序的相同调用中宏setjmp的最近一次调用保存的环境。 24 * 由于它能绕过常规的函数调用和返回机制,因此函数longjmp能够在中断/信号和其余相关的函数的上下文环境中正确地执行。 25 * 函数longjmp不能让宏setjmp返回0,若是val为0,这宏setjmp返回1. 26 * 27 * 建议以如下标准方式使用: 28 * 1,把每一个对setjmp的调用分离到一个独立的小函数中。那样就会使出现动态声明的数据对象被longjmp调用恢复的状况减小到最少。 29 * 2,在一个switch语句的控制表达式中调用setjmp。 30 * 3,在switch语句的case 0(process)中调用的函数中执行因此实际的过程。 31 * 4,经过执行longjmp(1)调用,在任意位置报告错误而且从新启动process。 32 * 5,经过执行longjmp(2)调用,在任意位置报告错误并终止process。 33 * 34 * jmp_buf是一个数组类型。 35 * 在信号处理器的内部调用longjmp,会出警告。 36 * 37 * 惟一可靠的实现方式是汇编来实现。 38 * 39 */ 40 #ifndef MY_SETJMP_H_ 41 #define MY_SETJMP_H_ 42 #ifndef _YVALS_H_ 43 #include "yvals.h" 44 #endif 45 46 #define setjmp(env) my_setjmp(env) 47 typedef int jmp_buf[NSETJMP]; 48 void longjmp(jmpbuf, int); 49 #endif
1 /*my_setjmp.c*/ 2 /* 3 * 演示版本,只为理解逻辑含义。 4 * 假设它能够把栈的一个连续的空间复制到jmp_buf数据对象中,而且能保存足够数量的调用环境。 5 * 它声明了不少register数据对象,但愿借此能够强制报存全部具备调用上下文的重要的寄存器。 6 * 它制造了一个调用dump函数的假象,这样就能够骗过了一些优化器,这些优化器可能判定那些寄存器从没有被使用过。 7 */ 8 #include "my_setjmp.h" 9 #include <string.h> 10 11 static void dump(int a, int b, int c, int d, int e, 12 int f, int g, int h, int i, int j) 13 { 14 } 15 static int getfp(void) 16 { 17 int arg; 18 return ((int)(&arg + _JBFP)); 19 } 20 int setjmp(jmp_buf env) 21 { 22 register int a = 0, b = 0, c = 0, d = 0, e = 0; 23 register int f = 0, g = 0, h = 0, i = 0, j = 0; 24 25 if(a) 26 dummy(a, b, c, d, e, f, g, h, i, j); 27 env[1] = getfp(); 28 memcpy((char *)&env[2], (char *)env[1] + _JBOFF, _JBMOV); 29 return 0; 30 }
1 /*my_longjmp.c*/ 2 #include "my_setjmp.h" 3 #include <string.h> 4 5 static void dummy(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) 6 { 7 } 8 static void setfp(int fp) 9 { 10 int arg; 11 (&arg)[_JBFP] = fp; 12 } 13 static int dojmp(jmp_buf env) 14 { 15 memcpy((char *)env[1] + _JBOFF, (char *)&env[2], _JBMOV; 16 setfp(env[1]); 17 return (env[0]); 18 } 19 void longjmp(jmp_buf env, int val) 20 { 21 register int a = 0, b = 0, c = 0, d = 0, e = 0; 22 register int f = 0, g = 0, h = 0, i = 0, j = 0; 23 24 if(a) 25 dummy(a, b, c, d, e, f, g, h, i, j); 26 env[0] = val ? val :1; 27 dojmp(env); 28 }
1 /*my_t_setjmp.c*/ 2 #include <assert.h> 3 #include "my_setjmp.h" 4 #include <stdio.h> 5 6 static int ctr; 7 static jmp_buf b0; 8 9 static void jmpto(int n) 10 { 11 longjmp(b0, n); 12 } 13 static char *stackptr(void) 14 { 15 char ch; 16 return (&ch); 17 } 18 static int tryit(void) 19 { 20 jmp_buf b1; 21 char *sp = stackptr(); 22 23 ctr = 0; 24 switch(setjmp(b0)){ 25 case 0: 26 assert(sp == stackptr()); 27 assert(ctr == 0); 28 ++ctr; 29 jmpto(0); 30 break; 31 case 1: 32 assert(sp == stackptr()); 33 assert(ctr == 1); 34 ++ctr; 35 jmpto(2); 36 break; 37 case 2: 38 assert(sp == stackptr()); 39 assert(ctr == 2); 40 ++ctr; 41 switch(setjmp(b1)){ 42 case 0: 43 assert(sp == stackptr()); 44 assert(ctr == 3); 45 ++ctr; 46 longjmp(b1, -7); 47 break; 48 case -7: 49 assert(sp == stackptr()); 50 assert(ctr == 4); 51 ++ctr; 52 jmpto(3); 53 case 5: 54 return (13); 55 default: 56 return (0); 57 } 58 case 3: 59 longjmp(b1, 5); 60 break; 61 } 62 return -1; 63 } 64 int main() 65 { 66 assert(tryit() == 13); 67 printf("sizeof(jmp_buf) = %u\n", sizeof(jmp_buf)); 68 puts("success testing 'setjmp.h'"); 69 return 0; 70 }