您好,登錄后才能下訂單哦!
1、語言本身沒有異常處理的原則。
一、異常的概念:
1、程序在運行過程中可能產生異常。
2、異常(Exception)與Bug的區別
@1:異常是程序運行時可預料的執行分支。是我們在程序開發時要考慮的一些特殊情況
@2:Bug是程序中的錯誤,是不可被預期的運行方式
二、異常(Exception)和Bug的對比
1、異常的例子:
(1)運行時產生除0的情況
(2)需要打開的外部文件不存在
(3)數組訪問越界
2、bug的例子:
(1)使用了野指針
(2)堆數組使用結束后未釋放
(3)選擇排序無法處理長度為0的數組
三、C語言經典處理異常的方式:if...else...
1、
void func(...)
{
if (判斷是否產生異常)
{
正常情況的代碼邏輯;
}
else
{
異常情況代碼邏輯;
}
}
四、編程實踐一下異常處理
1、在C語言中,除法操作異常處理(除數為0的情況),不是完美的方法
例:
#include <stdio.h>
/*
* C語言中對除數為0情況下的異常處理方法,不是完美的方法
*
*/
static double divide(double a, double b, int *valid) //用valid表示異常是否發生,1為沒發生、0為發生
{
const double delta = 0.000000000001;
double ret = 0;
if (!((-b < delta) && (b < delta)))
{
*valid = 1;
ret = a / b;
}
else
{
*valid = 0;
}
return ret;
}
inline static int char_to_num(const char c)
{
return (c - 48);
}
int main(int argc, char *argv[])
{
int valid = 0;
double r = 0;
#if 0
if (2 == argc)
{
printf("argc = %d. argv[1][0] = %d.\n", argc, argv[1][0]);
}
#endif
r = divide(char_to_num(argv[1][0]), char_to_num(argv[1][1]), &valid);
if (valid)
{
printf("r = %f.\n", r);
}
else
{
printf("Divide operator error, by zero.\n");
}
// printf("char_to_num(%c) = %d.\n", '1', char_to_num('9') );
return 0;
}
2、上面例子處理除數為0的異常情況的缺陷:
(1)divide函數有三個參數,難以理解其用法
(2)divide函數調用后必須判斷valid代表的結果
@1:當vaild為true時,運算結果正常
@2:當vaild為false時,運算過程出現異常
3、所以我們要將上面的divide函數的缺陷彌補起來,使其只有兩個參數,用起來方便。
(1)C語言提供了兩個函數:setjmp()和longjmp()進行優化。但是這兩個函數不要隨意的調用,因為這兩個函數簡單出爆,將破壞結構化程序設計的特性
在<csetjmp>頭文件中
@1:
int setjmp(jmp_buf env)
:將當前上下文保存在jmp_buf結構體中
@2:
void longjmp(jmp_buf env, int val)
:從jmp_buf結構體中恢復setjmp()保存的上下文
:最終從setjmp函數調用點返回,返回值為val
(2)利用setjmp()和longjmp()函數來節省divide函數對除數為0情況時的異常處理,但這個方法也不好。
例:
#include <stdio.h>
#include <setjmp.h>
/*
* C語言中對除數為0情況下的異常處理方法,這個方法也不好,還不如用三個參數的divide解決
*
*/
static jmp_buf jmpbuff;
static double divide(double a, double b) //用valid表示異常是否發生,1為沒發生、0為發生
{
const double delta = 0.000000000001;
double ret = 0;
if (!((-b < delta) && (b < delta)))
{
ret = a / b;
}
else
{
longjmp(jmpbuff, 1); //代碼如果執行到這里,調用這個函數時,會跳轉到setjmp這個函數調用的位置,并且這時setjmp函數的返回值為這個longjmp函數的第二個參數值
}
return ret;
}
inline static int char_to_num(const char c)
{
return (c - 48);
}
int main(int argc, char *argv[])
{
#if 0
if (2 == argc)
{
printf("argc = %d. argv[1][0] = %d.\n", argc, argv[1][0]);
}
#endif
if (setjmp(jmpbuff) == 0)
{
printf("num = %f.\n", divide((double)char_to_num(argv[1][0]), (double)char_to_num(argv[1][1])));
}
else
{
printf("Divide operator error, by zero.\n");
}
// printf("char_to_num(%c) = %d.\n", '1', char_to_num('9') );
return 0;
}
(3)使用setjmp()和longjmp()的缺陷
@1:必然涉及到使用一個jmp_buf類型的全局變量
@2:暴力跳轉導致代碼可讀性降低。
@3:本質還是if...else...異常處理方式,C語言中處理異常方式的經典方法。
(3)C語言中的經典異常處理方式會使得程序邏輯中混入大量的處理異常的代碼, 正常邏輯代碼和異常處理代碼混合在一起,導致代碼迅速膨脹,難以維護。
4、C++中有沒有更好的異常處理方式呢?
(1)答案是有的,C++語言中已經將直接將異常的概念內置于語法當中了。可以通過關鍵字就可以看出來哪些代碼是處理正常功能的代碼,哪些代碼是進行異常處理的代碼。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。