前言
?? 這篇博客來聊一聊C/C++的斷言機制。
?? 嵌入式驅動學習專欄將詳細記錄博主學習驅動的詳細過程,未來預計四個月將高強度更新本專欄,喜歡的可以關注本博主并訂閱本專欄,一起討論一起學習。現在關注就是老粉啦!
目錄
- 前言
- 1. 斷言介紹
- 1.1 斷言的概念
- 1.2 斷言的實現
- 1.3 禁用斷言
- 2. 靜態斷言
- 2.1 使用案例
- 2.2 優點
- 3. 運行時斷言
- 3.1 assert使用
- 3.2 assert注意事項
- 參考資料
1. 斷言介紹
1.1 斷言的概念
?? 斷言就是用于在代碼中捕捉這些假設,可以將斷言看作是異常處理的一種高級形式。
?? 斷言表示為一些布爾表達式,程序員相信在程序中的某個特定點該表達式值為真。可以在任何時候啟用和禁用斷言驗證,因此可以在測試時啟用斷言,而在部署時禁用斷言。
?? 最終用戶在遇到問題時可以重新起用斷言。它可以快速發現并定位軟件問題,同時對系統錯誤進行自動報警。斷言可以對在系統中隱藏很深,用其它手段極難發現的問題可以用斷言來進行定位,從而縮短軟件問題定位時間,提高系統的可測性。
?? 斷言的本質就是if ... else ...
判斷:
if (假設為true) {程序正常運行;
} else {報錯并終止程序
}
?? 那為什么還要斷言呢?如果全是if ... else...
的話就會有無數個if
語句,甚至可能一個if語句的作用閾從文件頭到文件尾。并且使用斷言的時機,大部分都是偶然事件,只是要驗證的假設,僅僅想測試一下最壞的情況是否發生。
?? 除此以外,斷言的assert()宏只有Debug版本才有效,Release中則被忽略。
1.2 斷言的實現
?? 在使用斷言時,需要添加頭文件:#include <assert.h>
?? 斷言是assert(expression)
,這是一個宏!!!!
void assert( int expression );
?? assert
計算表達式,如果值為假,那么先想stderr
打印一條錯誤信息,然后調用abort
來終止程序運行。
1.3 禁用斷言
?? 調試結束后,可以在#include語句之前插入#define NDEBUG來禁用assert調用:
#define NDEBUG
#include <assert.h>
2. 靜態斷言
2.1 使用案例
?? 靜態斷言主要是用來約束程序在編譯時要滿足的一定要求,是在c++11中引入的。
?? 其定義如下所示:
static_assert(常量表達式,提示字符串);
?? 如果第一個參數常量表達式的值為真(true或者非零值),那么static_assert
不做任何事情,就像它不存在一樣,否則會產生一條編譯錯誤,錯誤位置就是該static_assert
語句所在行。錯誤提示就是第二個參數提示字符串。
#include <assert.h>int main(void) {static_assert(false, "This is an error");return 0;
}
?? 在IDE中就會報錯提示。并且下面的錯誤提示就是后面自己寫的錯誤提示。
2.2 優點
1、使用
static_assert
,我們可以在編譯期間發現更多的錯誤,提前找出錯誤的原因。
??
2、static_assert
可以用在全局作用域中,命名空間中,類作用域中,函數作用域中,幾乎可以不受限制的使用。
??
3、編譯器在遇到一個static_assert
語句時,通常立刻將其第一個參數作為常量表達式進行演算,但如果該常量表達式依賴于某些模板參數,則延遲到模板實例化時再進行演算,這就讓檢查模板參數成為了可能。
??
4、由于之前有望加入C++0x標準的concepts提案最終被否決了,因此對于檢查模板參數是否符合期望的重任,就要靠static_assert來完成了,所以如何構造適當的常量表達式,將是一個值得探討的話題。
??
5、性能方面,由于是static_assert編譯期間斷言,不生成目標代碼,因此static_assert不會造成任何運行期性能損失
3. 運行時斷言
3.1 assert使用
?? 運行時斷言可以在程序運行過程中,判斷一些支持程序正常運行的假設性條件是否滿足。
?? 上面1.3中的assert
宏就是動態斷言
3.2 assert注意事項
?? 可以在函數開始處檢驗傳入參數的合法性
int readNum(int n) {assert(n > 0);return 1;
}
?? 每個assert
只檢驗一個條件,因為同時檢驗多個條件時,如果斷言失敗,無法直觀的判斷是哪個條件失敗
// 不要寫成這樣
assert(n > 0 && n < maxBound);
// 最好寫成這樣
assert(n > 0);
assert(n < maxBound);
?? 不能使用改變環境的語句,因為assert
只在DEBUG
個生效,如果這么做,會使用程序在真正運行時遇到問題
// 不要寫成這樣
assert(i++ > 10);
// 最好寫成這樣
assert(i > 10);
i++;
?? assert
和后面的語句應空一行,以形成邏輯和視覺上的一致感
?? 有的地方,assert
不能代替條件過濾
參考資料
[1] C語言之斷言的一些理解
[2] c++11中靜態斷言static_assert