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 }
相关文章
相关标签/搜索