第63課-C語言異常處理
阿新 • • 發佈:2018-12-12
一、異常處理
1. 異常的概念
- 程式在執行過程中可能產生異常
- 異常(Exception)與Bug的區別
- 異常時程式執行時可預料的執行分支
- Bug是程式中的錯誤,是不被預期的執行方式
2. 異常(Exception)和Bug的對比
- 異常
- 執行時產生除0的情況
- 需要開啟的外部檔案不存在
- 陣列訪問時越界
- Bug
- 使用野指標
- 堆陣列使用結束後未釋放
- 選擇排序無法處理長度為0的陣列
3. C語言經典處理方式
if…else…
if( ){ //判斷是否產生異常
// 正常情況程式碼邏輯;
}
else{
//異常情況程式碼邏輯;
}
程式設計實驗:除法操作異常處理
#include<iostream>
using namespace std;
double divide(double a,double b,int* valid){
const double delta = 0.00000000000001;
double ret = 0 ;//儘可能避免兩個浮點數直接進行比較,二者的數值表達很容易不準確
if((!(-delta < b) && (b < delta))){
ret = a / b;
*valid = 1 ;
}
else{
*valid = 0;
}
return ret;
}
int main(int argc,char *argv[]){
int valid = 0;
double r = divide(1,0,&valid);
if(valid){
cout << "r = " << r << endl;
}
else{
cout << "Divided by zero..." << endl;
}
return 0;
}
列印結果:
Divided by zero...
二、異常處理的方式
缺陷
divide
函式有3個引數,難以理解其用法divide
函式呼叫後必須判斷valid
代表的結果
- 當
valid
為true
時,運算結果正常 - 當
valid
為false
時,運算結果出現異常
- 當
通過setjmp()
和longjmp()
進行優化
int setjmp(jmp_buf env)
- 將當前上下文儲存在jmp_buf結構體中
void longjmp(jmp_buf env,int val)
- 從
jmp_buf
結構體中恢復setjmp()
儲存的上下文 - 最終從
setjmp
函式呼叫點返回,返回值為val
- 從
程式設計實驗:除法操作異常處理優化
#include<iostream>
#include<csetjmp>
using namespace std;
static jmp_buf env; //宣告靜態全域性變數
double divide(double a,double b){
const double delta = 0.0000000000000001;
double ret = 0;
if(!((-delta < b) && (b < delta))){
ret = a / b;
}
else{
longjmp(env,1); //2. 跳轉到第20行
}
return ret;
}
int main(){
if( setjmp(env) == 0){ //3.返回值為1,不滿足,執行第24行
double r = divide(1,0); //1.執行到該步時呼叫函式divide(),發現異常,執行到第14行時返回到20行
cout << "r = " << r << endl;
}
else{ //4. 由第20行跳轉得到
cout << "Divided by zero..." << endl;
}
return 0;
}
列印結果:
Divided by zero...
缺陷:
setjmp()
和longjmp()
的引入:
- 必然涉及到使用全域性變數
- 暴力跳轉導致程式碼可讀性降低
- 本質還是if…else…異常處理方式
注:C語言中的經典異常處理方式會使得程式中邏輯中混入大量的處理異常的程式碼。
正常邏輯程式碼和異常處理程式碼混合在一起,導致程式碼迅速膨脹,難以維護。。。
三、總結
- 程式中不可避免地會發生異常
- 異常是在開發階段就可以預見的執行時問題
- C語言中通過經典的
if...else...
方式處理異常 - C++中存在更好的異常處理方式