C介面與實現—C裡面的異常處理機制

lzh2nix發表於2019-05-11

我們的程式為什麼總是bug不斷?

我們的程式通常會出現三個錯誤: 使用者輸入錯誤, 執行期錯誤以及異常。對於使用者輸入錯誤我們會進行很多的合法性檢查,一般都是可以避免的,對於執行期錯誤就比較難辦了,我們是最希望把bug在前期的過程的發現,如果需求期的一個bug流入到生產環境中的話那麼損失就是無法估量的,客戶可能會直接懷疑你家的設計能力。儘管我們都在層層的把關,還是有很多的bug會遺留到生產系統上去。

對執行期錯誤我們能做的是就是做盡量多的測試(UT/FT/ST 等等),儘可能的去測試各種user case。也做了很多的測試但是線上系統還是有很多處理不完的bug,agile是不是正的適合大型軟體的開發,真的是不是每個人都能成為真正的全能手。這章主要是程式的異常處理和斷言。怎樣讓系統檢測到異常後進行合理的結束,並不是直接的crash,這裡還是有很多的學問, 不同與erlang中的 let it crash, C裡面提供了很多的異常處理機制,下面我們就來看看C中有那些合理的處理機制。

第一個就是longjmp和setjmp, 一個結構化的異常處理,setjmp設定一個異常處理點,然後發生異常的時候longjmp到之前set的地方,下面是一個簡單的例子,我們檢測除法異常如果除數為0我們則jmp到之前set的地方。

#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>

int div_by_zero_handled = 0;
jmp_buf Div_Failed;

int div(int n, int m) {
  if (m == 0) {
    if (div_by_zero_handled) {
      longjmp(Div_Failed, 1);
    }
  }
  return n / m;
}

int main() {
  div_by_zero_handled = 1;
  if (setjmp(Div_Failed)) {
    printf("can`t div by zero 
");
    exit(EXIT_FAILURE);
  }
  
  int n = div(2, 0);
  printf("----->%d
", n);

  return 0;
}

這裡如果在div裡面我們檢測到除數是0, 那麼longjump到之前set的地方, 程式的輸出如下:

can`t div by zero

下面就來看看在C語言裡面這樣通過longjmp和setjmp和巨集實現一個類似C++ java中 try catch的功能。但這裡需要強調一點的是異常處理要儘量的少用,正如書中所講的一般只在大型應用程式中少量的使用,如果異常越來越多,這通常說明程式有更嚴重設計問題。

C++/java中的try catch 的語法是這樣的:

try 
    S
catch (e1)
    S1
catch (e2)
    S2
catch (en)
    Sn
Else
    So

在e1, e2, en的地方我們通過setjmp建立了異常處理程式,如果S沒有觸發異常,將跳過程式程式,如果在S執行過程中產生了異常e,並且e是在e1…en之間的一個,那麼S的執行被中斷,控制立即轉給相對應的Except從句總的語句。

最後還是要切記,在程式碼中異常處理要儘量少用。

-END-

相關文章