zoukankan      html  css  js  c++  java
  • setjmp()和longjmp()函数

    之前我们讲到了过程活动记录(AR),那么如何来操纵AR呢,一个可能的方法是,根据局部变量的地址进行推算,例如对于上面的a函数,执行a函数时的当前AR地址就是参数i的地址偏移8个字节,也就是 ((char*)&i) - 8。

    然而,不同的C编译器,以及不同的硬件平台都会产生不同的AR结构布局,甚至在一些平台上,AR根本不会存放到Stack中(也可能放在寄存器里,这样运行速度更快一点)。所以这种方式操纵AR是不通用的。

    为此,C语言通过库函数的方式提供了操纵AR的统一方法,那就是setjmp和longjmp函数。

    (注意:goto语句不能跳出C语言当前的函数

    1. 作用:

    setjmp()和longjmp() 可以实现非局部控制转移即从一个函数到另外一个函数的跳转。

    2. 函数原型:

    int setjmp(jmp_buf j);
    void longjmp(jmp_buf j, int i);


    setjmp函数设置返回点,保存调用函数的栈环境与j中(相当于保护现场)。 l

    ongjmp的作用是使用setjmp保存在j中的栈环境信息返回到setjmp的位置,也就是当执行longjmp时程序又回到setjmp处(相当于恢复现场)。

    setjmp有两个作用:

    1)保存调用函数的栈环境于j中,返回值为0

    2)作为longjmp的返回目标地,返回值为longjmp的第二个参数i,使代码能够知道它是实际上是通过longjmp返回的

    当然,当使用longjmp()时,j的内容被销毁。

    3. jmp_buf数据类型

    typedef struct __jmp_buf_tag jmp_buf[1];

    jmp_buf实际是一个数组,内存分配在栈空间中,作为参数传递时是一个指针(指向调用函数的栈帧)。

    4. 具体实例

    #include <stdio.h>
    #include <setjmp.h>
    jmp_buf buf;
    void haha()
    {
        printf("in haha()
    ");
        longjmp(buf,1);
        printf("kaonima
    ");
    }
    int tim=0;
     
    int main()
    {
        if(setjmp(buf))
        {
            printf("back in main
    ");
            tim++;
        }
        else
        {
            printf("first time through
    ");
            haha();
        }
        if(tim<3) longjmp(buf,1);
        return 0;
    }

    运行结果是:

    first time through
    in haha()
    back in main
    back in main
    back in main

    6.异常处理

    这里举一个使用这两个函数进行异常处理的例子

    #include <stdio.h>
    #include <stdlib.h>
    #include <setjmp.h>
    
    jmp_buf jb;
    
    void f1()
    {
        printf("进入f1()
    ");
        if(0/*正确执行*/){ }
        else {
            longjmp(jb,1);
        }
        printf("退出f1()
    ");
    }
    void f2()
    {
        printf("进入f2()
    ");
        if(1/*正确执行*/) {  }
        else {
            longjmp(jb, 2);
        }
        printf("退出f2()
    ");
    }
    
    int main()
    {
        int r = setjmp(jb);
        if(r==0){
            f1();
            f2();
        }else if(r==1){
            printf("处理错误1
    ");
            exit(1);
        }else if(r==2){
            printf("处理错误2
    ");
            exit(2);
        }
        return 0;
    }

    当然完整的异常处理远比这里的代码要复杂,需要考虑异常的嵌套等,这里仅仅给出最简单的思路。

    注:不要在C++中使用setjmp和longjmp

    C++为异常处理提供了直接支持。除非极特殊需要,不要再重新实现自己的异常机制,尤其需要说明的是,简单的调用setjmp/longjmp有可能带来问题。

    #include <stdio.h>
    #include <stdlib.h>
    #include <setjmp.h>
    
    class MyClass
    {
    public:
        MyClass(){ printf("MyClass::MyClass()
    ");}
        ~MyClass(){ printf("MyClass::~MyClass()
    ");}
    };
    jmp_buf jb;
    
    void f1()
    {
        MyClass obj;
        printf("进入f1()
    ");
        if(0/*正确执行*/){ }
        else {
            longjmp(jb,1);
        }
        printf("退出f1()
    ");
    }
    void f2()
    {
        printf("进入f2()
    ");
        if(1/*正确执行*/) {  }
        else {
            longjmp(jb, 2);
        }
        printf("退出f2()
    ");
    }
    
    int main()
    {
        int r = setjmp(jb);
        if(r==0){
            f1();
            f2();
        }else if(r==1){
            printf("处理错误1
    ");
            exit(1);
        }else if(r==2){
            printf("处理错误2
    ");
            exit(2);
        }
        return 0;
    }

    g++编译,程序输出:

    MyClass::MyClass()
    进入f1()
    处理错误1

    vc++编译,程序输出:

    MyClass::MyClass()
    进入f1()
    MyClass::~MyClass()
    处理错误1

    longjmp()跳转前局部对象可能并不会析构(g++),也可能析构(VC++),C++标准对此并无明确要求。这种依赖于具体编译器版本的代码是应该避免的。

    而C++本身的throw关键字,却能严格保证局部对象构造和析构的成对调用。

    参考:

    https://blog.csdn.net/smstong/article/details/50728022

    https://blog.csdn.net/c1194758555/article/details/52780068

    https://blog.csdn.net/qq_33656136/article/details/52732970

    C专家编程 6.8节

  • 相关阅读:
    杭电 Problem
    杭电Problem 5053 the sum of cube 【数学公式】
    杭电 Problem 2089 不要62 【打表】
    杭电 Problem 4548 美素数【打表】
    杭电 Problem 2008 分拆素数和 【打表】
    杭电 Problem 1722 Cake 【gcd】
    杭电 Problem 2187 悼念512汶川大地震遇难同胞——老人是真饿了【贪心】
    杭电Problem 1872 稳定排序
    杭电 Problem 1753 大明A+B
    东北林业大 564 汉诺塔
  • 原文地址:https://www.cnblogs.com/zzdbullet/p/9932122.html
Copyright © 2011-2022 走看看