setjmp.h(c標準庫)

 主要看了思路,代碼未測試。數組

 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 }
相關文章
相關標籤/搜索