主要看了思路,代碼未測試。數組
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 }