2011-05-14 102 views
3

可能重複:
Error handling in C code處理C語言錯誤的樣式?

你好的人。我使用C來處理一些小型項目,我看到它是如何的,因爲它沒有專門的錯誤處理結構,所以我必須用額外的條件塊來污染我的算法。我的問題是你如何更好地處理錯誤,並說明爲什麼。我在兩種方式之間撕裂......如果你有第三種方式,請發佈。謝謝。

/////////////////////////////////////////// 
// method 1 

// stuff that can go wrong; 

if (test1 == failed) 
{ 
    // print error; 
    // exit; 
} 
else 
{ 
    // more stuff that can go wrong; 

    if (test2 == failed) 
    { 
     // print error; 
     // exit; 
    } 
    else 
    { 
     // ... and so on... 
    } 
} 

/////////////////////////////////////////// 
// method 2 

// stuff that can go wrong; 

if (test1 == failed) 
{ 
    // print error; 
    // exit; 
} 

// more stuff that can go wrong; 

if (test2 == failed) 
{ 
    // print error; 
    // exit; 
} 

// ... and so on... 
+0

我會建議使用第二種風格,因爲它不會影響您的意圖。但我想這只是一個問題。 – Constantinius 2011-05-14 21:22:35

回答

0

我寧願使用這樣的:

if (test1 == failed) 
{ 
    // print error; 
    // exit; 
} 
else if (test2 == failed) 
{ 
    // print error; 
    // exit; 
} 
else 
{ 
    // ... and so on... 
} 

這是更具可讀性和它限制縮進。這也清楚地表明,如果一個條件失敗了,它將嘗試所有其他條件直到最終失敗;沒有機會同時滿足2個條件。

+0

然而,有更多的東西可以出錯,所以你不能以一種很好的方式真正做到這一點。 – 2011-05-14 21:25:14

+0

總有更多的東西可能會出錯:)。 – alex 2011-05-14 21:28:19

5

有些人不會同意我這一點,但我使用goto's。每個函數裏面,最後我在它看起來像這樣

if (0) 
{ 
ERROR: 
    // Handle errors, and exit/return after potentially freeing resources 
} 

然後我用if (something_bad) goto ERROR;沒有別人的或其他的東西到底有塊。

許多人不喜歡goto的,但這是這樣做的方式,而不是重複代碼。如果你真的堅持不使用goto語句的我會做到這一點:

#define LOCAL_ASSERT(COND) if (COND) { \ 
    /* Handle errors, and exit/return after potentially freeing resources */ \ 
} 

添加在每個函數的開頭定義它,然後添加在函數的末尾添加#undef LOCAL_ASSERT。這允許在每個函數處進行不同的錯誤處理,而不用不同的宏名稱來污染整個程序。

然後我簡單地使用LOCAL_ASSERT(cond)無處不在。

編輯:使自己更清晰,這是爲了節省多次編寫錯誤處理代碼。如果你想要小的定製,很容易設置一個錯誤變量字符串(或者將它作爲宏參數添加)。我只是不喜歡這樣的事情。我通常做

// method 1 
if (error) goto ERROR; // no else 

// method 2 
LOCAL_ASSERT(cond); 

Elses會污染你的代碼,並需要更多的縮進,這有時是煩人的。

0

我對方法2投了票。正如你所提到的,方法1中的錯誤處理掩蓋了「真實」算法的邏輯。

1

我知道這是用戶偏好一些,但我確實努力從每個功能建立退出點,或至多兩個出口點(但必須是明顯和容易斷點):

const Bool funcFoo(int someval, int someval2, int someval3) 
{ 
    if(someval == okval) 
    { // We're ok 
    if(someval2 == okval2) 
    { // Still ok. 
     if(someval3 == okval3) 
     { // Yippee! We made it! 
     return True; // <===== ONLY SUCCESS RETURN POINT 
     } 
    } 
    } 
    // Houston, we had a problem. 
    return False; // <===== ONLY FAIL RETURN POINT 
} 

在有「else」的問題,這是一個類似解纏的情況,但我們只保留兩個返回點:

const Bool funcFoo(int someval, int someval2, int someval3) 
{ 
    if(someval == okval) 
    { // We're ok 
    if(someval2 == okval2) 
    { // Still ok. 
     if(someval3 == okval3) 
     { // Yippee! We made it! 
     return True; // <===== ONLY SUCCESS RETURN POINT 
     } 
     else 
     { // someval3 is bad. 
     //...maybe handle, not return. 
     } 
    } 
    else 
    { // someval2 is bad. 
     // ...maybe handle, not return. 
    } 
    } 
    else 
    { // someval is bad. 
    // ...maybe handle, not return. 
    } 
    // Houston, we had a problem. 
    return False; // <===== ONLY FAIL RETURN POINT 
} 

幾件事情要提:

  1. 一個返回點是最好的。兩個 返回點是可以接受的,如果他們 是顯而易見的(您的錯誤通常要求退貨或失敗繼續)。
  2. 有時「else」僅用於 調試的目的,在此 點我包起來#ifdef _DEBUG ... #endif
  3. 有時「測試」應該是 成功,有時失敗, 取決於哪個是最 適合嵌套。
  4. 此方法(嵌套測試)是 有時與連續測試 連接。但是,嵌套測試通常優選爲 。