複製鏈接
請複製以下鏈接發送給好友

assert.h

鎖定
assert.h常用於防禦式編程。參數布爾表示式,消息。
外文名
assert.h
常用於
防禦式編程
參    數
布爾表示式,消息
特    點
可以使用斷言
assert.h 
一個布爾表達式的反面表示了一個錯誤。C 標準庫提供了一個 assert 宏,它只帶有一個參數,用法如下:
assert(1 == 0); // 注意 boolean expression 不要加引號
使用 assert 宏,需要包含頭文件 cassert 或者 assert.h,執行上面語句的結果是程序終止運行,輸出與下面消息類似的消息:
Assertion failed: 1 == 0, file d:\我的文檔\visual studio projects\learning\assert\assert.cpp, line 9
通常來説,我們會定義自己的 assert 宏,其目的有兩個:
(1)新增參數,例如新增一個消息參數,使得 assert 宏輸出更為豐富的信息。
(2)改變 assert 的行為內容。C 標準庫中的 assert 宏將中斷程序,實際上,我們可以讓程序繼續運行而不中斷或者進入調試狀態等,另外還可以控制消息輸出的目標,即控制消息是輸出到控制枱還是文本文件,甚至是通過網絡發出。
下面是一個 C++ 實現的斷言:
  #ifdef _DEBUG
  #define Assert(exp, message) \
  { \
  if (!(exp)) \
  { \
    std::cout << "Assertion failed: " << #exp << "\n" \
      << "Message: " << message << "\n" \
      << "line: " << __LINE__ << "\n" \
      << "file: " << __FILE__ << "\n"; \
        exit(EXIT_FAILURE); \
   } \
   }
#else
  #define Assert(exp, message)
#endif
執行 Assert(1 == 0, "Error"); 結果為:
Assertion failed: 1 == 0
Message: Error
line: 24
file: d:\我的文檔\visual studio projects\learning\assert\assert.cpp
使用斷言應該注意一下的幾個問題:
1、對非預期錯誤使用斷言
斷言中的布爾表達式的反面一定要描述一個非預期錯誤,下面所述的在一定情況下為非預期錯誤的一些例子:
(1)空指針
(2)輸入或者輸出參數的值不在預期範圍內。
(3)數組的越界。
非預期錯誤對應的就是預期錯誤,我們通常使用錯誤處理代碼來處理預期錯誤,而使用斷言處理非預期錯誤。在代碼執行過程中,有些錯誤永遠不應該發生,這樣的錯誤是非預期錯誤。斷言可以被看成是一種可執行的註釋,你不能依賴它來讓代碼正常工作。例如:在
int nRes = f(); // nRes 由 f 函數控制, f 函數保證返回值一定在 -100 ~ 100
Assert(-100 <= nRes && nRes <= 100); // 斷言,一個可執行的註釋
由於 f 函數保證了返回值處於 -100 ~ 100,那麼如果出現了 nRes 不在這個範圍的值時,就表明一個非預期錯誤的出現。後面會講到“隔欄”,那時會對斷言有更加深刻的理解。
2、不要把需要執行的代碼放入斷言中
斷言用於軟件的開發和維護,而通常不在發行版本中包含斷言。
需要執行的代碼放入斷言中是不正確的,因為在發行版本中,這些代碼通常不會被執行,例如:
Assert(f()); // f 函數通常在發行版本中不會被執行
而使用如下方法則比較安全:
res = f();
Assert(res); // 安全
3、對來源於內部系統的可靠的數據使用斷言,而不要對外部不可靠的數據使用斷言,對於外部不可靠數據,應該使用錯誤處理代碼。再次強調,把斷言看成可執行的註釋。
前條件(preconditions)和後條件(postconditions)
前條件是調用方代碼在調用例程(routines)或者實例化對象之前要確保為真的條件,後條件是例程執行後或者類實例化後應滿足的條件。下面是一個例子:
// 前條件,這裏 nNum1 和 nNum2 的取值被前面代碼所約束並保證取值在 -50 ~ 50
Assert(-50 <= nNum1 && nNum1 <= 50, "Add_nNum1");
Assert(-50 <= nNum2 && nNum2 <= 50, "Add_nNum2");
int nRes = add(nNum1, nNum2);
// 後條件
Assert(-100 <= nRes && nRes <= 100, "Add_nRes");
注意,由於 nNum1 和 nNum2 取值範圍已經被約束,因此可以使用斷言,但是如果 nNum1 和 nNum2 的值來源於不可靠的外部系統,那麼應該使用錯誤處理代碼,而不是使用斷言。