《C语言杂记》C语言异常处理之 setjmp()和longjmp()

Posted Bruceoxl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《C语言杂记》C语言异常处理之 setjmp()和longjmp()相关的知识,希望对你有一定的参考价值。

异常处理之除0情况

相信大家处理除0时,都会通过函数,然后判断除数是否为0,代码如下所示:

double divide(double a,double b)
{
    const double delta = 0.00000000001;         //由于浮点数不精确,所以需要定义个很小的数  
    if(!((-delta<b)&&(b<delta)))
    {
        return  a/b ;
    } 
    else 
    { 
       return 0; 
    }  
}

其实这个函数还有瑕疵,当我们调用divide(0,1)时,返回值也是0,在程序运行时,根本无法判断返回值0是不是除法为0的原因。其实可以通过setjmp()和longjmp()配合使用。

描述

  • 和goto很相似, 但是可以从一个函数到另外一个函数的跳转,常常用在异常处理上面.
  • 这两个函数需要正确使用,否则会破坏程序顺序执行方式
  • 头文件 #include <setjmp.h>

setjmp()和longjmp()

int setjmp(jmp_buf env);

将当前上下文保存在jmp_buf结构体中(入栈),并返回0。

void longjmp(jmp_buf env,int val);

从env变量jmp_buf结构体中恢复setjmp()保存的上下文(出栈,并跳转)
由于跳转,所以会从setjmp函数调用点返回,返回值为val

跳转机制 (以 mian()函数 和 divide()函数 为例):

  • mian()函数 调用了 setjmp(env),将上下文(入栈)保存在env中,并返回0。
  • 接着调用 divide()函数进行除法操作。
  • 进入 setjmp()函数后,由于发现除法为0,所以使用 longjmp(env,1)函数,恢复 setjmp() 保存的上下文,也就是直接返回到了 main()函数处理 setjmp(env) 的时候,并返回异常值1。

’代码实现:

#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
double divide(double a,double b)
{
       const double delta = 0.00000000001;         //由于浮点数不精确,所以需要定义个很小的数
       if(!((-delta<b)&&(b<delta)))
       {
              return  a/b ;
       }
       else
       {
           longjmp(env,1); //直接跳转到23行,ret=setjmp(env)代码处,并返回异常值(1)
           return 0;
       }
}
 
int main( )
{
    int ret;
 
    ret=setjmp(env); //手动调用 setjmp(),将返回正常值(0),
 
   if(!ret)            //正常操作
  {
    printf("5/0=%lf\\n",divide(5,0));
  }
   else if(ret==1)     //异常操作
    {
    printf("ERR\\n");
    } 
    return 0;
}

运行打印:
ERR

缺陷在于:

  • 若需要两个函数之间跳转,必然要使用全局变量jmp_buf env。
  • 跳转使得代码可读性降低。



欢迎访问我的网站

BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
BruceOu的知乎


欢迎订阅我的微信公众号

以上是关于《C语言杂记》C语言异常处理之 setjmp()和longjmp()的主要内容,如果未能解决你的问题,请参考以下文章

知识分享:C语言如何对异常进行捕获?

函数指针玩得不熟,就不要自称为C语言高手(函数指针是解耦对象关系的最佳利器,还有signal)

c语言异常怎么捕获有几种方式

《C语言杂记》编译优化之__builtin_expect

C++异常处理机制

C++异常处理机制