C 語言異常處理

C 語言異常處理

異常的概念

  • 程序在運行過程當中可能產生異常
  • 異常(Exception) 與 Bug 的區別html

    • 異常是程序運行使可預料的執行分支
    • Bug 是程序中的錯誤,是不被預期的運行方式

異常(Exception) 和 Bug 的對比

  • 異常ios

    • 運行時產生除 0 的狀況
    • 須要打開的外部文件不存在
    • 數組訪問時越界
  • Bug編程

    • 使用野指針
    • 堆數組使用結束後未釋放
    • 選擇排序沒法處理長度爲 0 的數組

C 語言經典處理方式: if ... else ...

void func(...)
{
    if(判斷是否產生異常)
    {
        正常狀況代碼邏輯
    }
    else
    {
        異常狀況代碼邏輯
    }
}

編程實驗1:除法操做異常處理

include <iostream>
#include <string>

using namespace std;

double divide(double a, double b, int* valid)
{
    const double delta = 0.000000000000001;
    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;
}

缺陷

  • divide 函數有 3 個參數,難以理解其用法
  • divide 函數調用後必需判斷 valid 表明的結果數組

    • 當 valid 爲 true 時,運行結果正常
    • 當 valid 爲 false 時,運算過程當中出現異常

異常處理優化

經過 setjmp()longjmp() 進行優化ide

  • int setjmp(jmp_buf env)

將當前上下文保存在 jmp_buf 結構體中函數

  • void longjmp(jmp_buf env, int val)學習

    • 從 jmp_buf 結構體中恢復 setjmp 保存上下文
    • 最終從setjmp 函數調用點返回,返回值爲 val

編程實驗2:除法操做異常處理優化

#include <iostream>
#include <string>
#include <csetjmp>

using namespace std;

static jmp_buf env;

double divide(double a, double b)
{
    const double delta = 0.000000000000001;
    double ret = 0;
    
    if( !((-delta < b) && (b < delta)) )
    {
        ret = a / b;
    }
    else
    {
        longjmp(env, 1);   // 根據 env 恢復上下文,出口時在 setjmp() 處,longjmp 函數的功能是從 jmp_buf 結構體中恢復由 setjmp 函數保存的上下文,該函數不返回,而是從 setjmp 函數中返回。
    }
    
    return ret;
}

int main(int argc, char *argv[])
{   
    if( setjmp(env) == 0 )   // 直接調用,將函數在此處的上下文保存在 env 這個變量裏,以供 longjmp 今後結構體中恢復。
    {
        double r = divide(1, 1);
        
        cout << "r = " << r << endl;
    }
    else
    {
        cout << "Divided by zero..." << endl;
    }
    
    return 0;
}

具體看以下連接: 優化

linkspa

缺陷

setjmp() 和 longjmp() 的引入指針

  • 必然涉及到使用全局變量
  • 暴力跳轉致使代碼可讀性下降
  • 本質仍是 if... else ... 異常處理方式

C語言處理的方式不是很好,會使得程序中邏輯中混入大量的處理異常的代碼。
正常邏輯代碼和異常代碼混合在一塊兒,致使代碼迅速膨脹 ,難以維護

實例分析代碼

#include <iostream>
#include <string>

using namespace std;

#define SUCCESS           0 
#define INVALID_POINTER   -1
#define INVALID_LENGTH    -2
#define INVALID_PARAMETER -3

int MemSet(void* dest, unsigned int length, unsigned char v)
{
    if( dest == NULL )
    {
        return INVALID_POINTER;
    }
    
    if( length < 4 )
    {
        return INVALID_LENGTH;
    }
    
    if( (v < 0) || (v > 9) )
    {
        return INVALID_PARAMETER;
    }
    
    unsigned char* p = (unsigned char*)dest;
    
    for(int i=0; i<length; i++)
    {
        p[i] = v;
    }
    
    return SUCCESS;
}

int main(int argc, char *argv[])
{
    int ai[5];
    int ret = MemSet(ai, sizeof(ai), 0);
    
    if( ret == SUCCESS )
    {
    }
    else if( ret == INVALID_POINTER )
    {
    }
    else if( ret == INVALID_LENGTH )
    {
    }
    else if( ret == INVALID_PARAMETER )
    {
    }
    
    return ret;
}

向上述代碼是一眼看不出正常邏輯的過程的,若是去別的公司看代碼代碼都是這樣就很難立刻知道正確邏輯是怎麼運行的,不利於快速上手代碼
C語言中中只能這樣,全部C++將C中很差的方式進行了升級

小結

  • 程序中不可避免的會發生異常
  • 異常是開發階段就能夠碰見的運行方式
  • C 語言中經過經典的 if...else...方式處理異常
  • C ++ 中存在更好的異常處理方式
相關文章
相關標籤/搜索