2009-12-26 63 views
4

閱讀雜項。與SDL開發相關的教程我發現了兩個不同的例子,以相同的方式做了相同的事情,但方式不同。我想知道從代碼「安全性」和可維護性的角度來看,你認爲哪兩個是正確的。如何使用C斷言來使代碼更安全?

在第一個示例,程序員不使用斷言在所有,但代碼看起來行(至少對於我的眼睛):

int main(){ 
     SDL_Surface *screen; 

     /** Initialize SDL */ 
     if(SDL_Init(SDL_INIT_VIDEO)!=0){ 
       fprintf(stderr,"Unable to initialize SDL: %s",SDL_GetError()); 
     } 
     atexit(SDL_Quit); 

     /** Sets video mode */ 
     screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE); 
     if(screen==NULL){ 
       fprintf(stderr,"Unable to set video mode: %s",SDL_GetError()); 
     } 

     return (0); 
} 

在第二示例中,程序員[其他]是使用不同的方法,像(代碼是不完全粘貼複製):

int main(){ 
     SDL_Surface* screen; 

     /** Initialize SDL */ 
     assert(SDL_Init(SDL_INIT_VIDEO)==0); 
     atexit(SDL_Quit); 

     /** Sets video mode */ 
     screen=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE); 
     assert(screen!=NULL); 

     return (0); 
} 

是否確定的,如果條件(從第一個例子)「替代」與斷言像在第二個例子嗎?

什麼是正確的策略(如果有的話)?

+0

如果SDL_Init()失敗,則atexit對()和SDL_SetVideoMode()調用不應該讓 - 第一版本應該或者出口()在打印語句之後,或者代碼應該用'else'寫入以覆蓋剩下的動作。 – 2009-12-26 20:39:02

回答

24

做這個替換是不行的。第二個示例是錯誤,因爲assert(x)被擴展爲沒有任何在非調試版本(當定義了NDEBUG時)。這意味着上面的assert中的指針檢查已從發佈版本中的代碼中移除。這絕對是錯誤的。因此,何時應該使用assert?對於記錄調試是有用的。在某種程度上,你說:「我確信這個條件是真的,並且把它作爲assert在調試過程中捕獲錯誤的代碼,並將條件記錄到代碼的讀者。」

所以,這兩個例子之間有很大的差異。對於檢查返回值malloc,assert是錯誤的,因爲不能保證它們會返回非NULL,正如我上面提到的,assert(x)意味着「我完全確信x是真實的」,而不僅僅是「If x是不正確的,這是不好的「。爲此,一個使用if(x) good(); else bad();控制。

SDL_InitSDL_SetVideoMode可以分別返回-1NULL

+4

assert()只能用於捕捉程序員的錯誤;它會通過崩潰程序發出這樣的錯誤信號,用2x4敲打程序員的頭部,並揮動大紅旗解釋擰緊的原因。這是一件很好的事情;參見David Thielen的書「No Bugs」,其中一章的標題是「斷言世界」。最終用戶在程序發行版中可能遇到的任何麻煩情況都應該儘可能地進行恢復處理,當然不要讓程序陷於火中。 – 2009-12-26 17:54:36

4

assert應該在出現意外情況時以意想不到的方式使用。通常,如果斷言失敗,則意味着程序中存在錯誤。斷言是而不是用於可能發生的預期錯誤(即無法打開文件,無法初始化某些內容等)。

在你介紹的例子中,assert似乎不是最合乎邏輯的解決方案。當程序無法初始化SDL時,以結構化的方式告訴用戶更有意義而不是拋出斷言(這可能導致某些系統出現seg-fault)。

3

斷言語句通常只用於調試構建,並會暫停程序,並經常允許您闖入調試器。在發佈版本中可能還是有意義的,以檢查錯誤情況。一種簡單的方法可能是這樣的:

assert(condition); 
if (!condition) 
    handle error; 
+0

可以嗎? assert和條件過程同時存在? – sevity 2009-12-26 16:57:05

+0

是的。斷言語句通常僅作爲if語句來實現。如果條件不成立,它會運行一些代碼(例如,__asm int 3;也許)。它只是意味着在調試版本中,它必須運行兩個if語句。 – 2009-12-26 17:15:31

+0

是的,如果您可以檢測並從錯誤狀態中恢復,那麼該代碼肯定應該在那裏。如果你不希望在實踐中出現這種錯誤,那麼斷言也是有意義的。 – 2009-12-27 02:47:09

1

我使用assertion來記錄先決條件和後置條件。 (函數的識別意圖)

如..

double positive_division(double dividend, double divisor) 
{ 
    //preconditions 
    ASSERT(dividend>=0); 
    ASSERT(divisor >0); 

    double quotient = dividend/divisor; 

    //postconditions  
    ASSERT(quotient>=0); 
    return quotient; 
}