Linux中的函数间跳转:setjmp()和longjmp()

        先来看个实例吧,在 用c++写的简易学生通讯录中有那么个实例:删除通讯录中某个人的号码;1、开始是主页面菜单函数,选择删除功能后;2、跳转到删除信息函数中,在这个函数中还要先调用查找函数;3、在查找函数中又要判断以什么方式查找(姓名还是学号);4、选择好查找方式以后,查找到该人信息返回;5、打印信息再次确认是否真的需要删除这些信息;6、删除后返回到主页面菜单函数;

        一个删除功能嵌套调用了这么多函数,假如在某个函数中出错了(或者我在第5步取消删除),又要一层层的返回。幸好Linux中提供了setjmp()和longjmp()函数,用来在函数间进行跳转的,这个跳转是没有返回的是重新跳转到设置点处;

        请看下面的实例:

#include
#include//主要为了提供exit()函数
#include//提供setjmp()和longjmp()函数以及jmp_buf数组类型
 
 jmp_buf buffer;//存放当前状态的数组类型
 
 static int global_static_a = 1;
 int global_a = 2;
 
 void test2()
 {
     longjmp(buffer, 2); 
 }
 
 void test1(int a, int b, int c, int d, int e, int f, int g)
 {
     printf("\nin test1:\n");
     printf("global_static_a = %d\n", a); 
     printf("global_a = %d\n", b); 
     printf("auto_a = %d\n", c); 
     printf("register_a = %d\n", d); 
     printf("volatile_a = %d\n", e); 
     printf("static_a = %d\n", f); 
 
     if (2 == g)
         longjmp(buffer, 1); 
     test2();
 }
 
 int main(int argc, char* argv[])
 {
     int ret;
     int auto_a = 3;
     register int register_a = 4;
     volatile int volatile_a = 5;
     static int   static_a = 6;
     if (1 == (ret = setjmp(buffer)))
     {
         printf("\nsetjmp test1:\n");
         printf("global_static_a = %d\n", global_static_a);
         printf("global_a = %d\n", global_a);
         printf("auto_a = %d\n", auto_a);
         printf("register_a = %d\n", register_a);
         printf("volatile_a = %d\n", volatile_a);
         printf("static_a = %d\n", static_a);
         exit(0);
     }else if ( 2 == ret)
     {
         printf("\nsetjmp test2:\n");
         return 0;
     }else;
 
     global_static_a *= 10;
     global_a *= 10;
     auto_a *= 10;
     register_a *= 10;
     volatile_a *= 10;
     static_a *= 10;
 
     test1(global_static_a, global_a, auto_a, register_a, volatile_a, static_a, argc);
     return 0;
 
 }

        上面的流程比较简单:主函数 ==》 test1() ==》 test2();为了显示能在多处地方设置跳转点,这里用了命令行参数。如果有2个参数,则在test1()中就跳转回去;否则在test2()函数中跳转;

        大概分析下这两个跳转函数的本质关系:


                            longjmp()调用之前                                              longjmp()调用之后

          栈的底部  ----------------------   高地址                 栈的底部   --------------------   高地址

                            |   main()的栈     |                                                   |  main()的栈    |

                            ----------------------                                                    --------------------

                            |   test1()的栈      |                                                  |        空栈          |  跳转后释放了test1()的栈空间 

                            ----------------------                                                    ---------------------

                            |   test2(0的栈     |                                                   |        空栈           | 跳转后释放了test2()的栈空间

                            ----------------------                                                    ---------------------

          栈的顶部   |                            |  低地址                                     |                          |       

        

        由上面的栈结构可以知道,longjmp()函数调用之后,其实质就是用esp回退到main函数中,清空掉test1() 和test2()的堆栈空间。


        根据结果顺便来分析回退到开始点处,各个变量是否改变。

        未优化的结果:

        Linux中的函数间跳转:setjmp()和longjmp()_第1张图片 

        优化后的结果:

        Linux中的函数间跳转:setjmp()和longjmp()_第2张图片

        根据两种结果可以知道寄存器变量和自动变量回退回去时,优化后得到的是个不确定的值;

        转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/43983809

        若有不正确之处,望大家指正,共同学习!谢谢!!!



你可能感兴趣的:(C语言,操作系统,unix环境高级编程)