異常處理之除0情況
相信大家處理除0時,都會通過函數,然后判斷除數是否為0,代碼如下所示:
double divide(doublea,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
- 跳轉使得代碼可讀性降低