很可笑,我很少用斷言,對斷言的不了解程度與初學者無異。今天翻看了《深入理解c++11》,新標準中對斷言做了改進,至少說明斷言還是很有用的。結合《**大全》、《c++應用程式效能優化》把自己對斷言的理解寫下來以方便自己日後用到時查閱。
一、為什麼要用斷言
首先要搞清楚為什麼要用斷言,不能看別人**中有,就追趕時髦地用一用!從效果上來說assert斷言能用if語句替換,那麼為什麼不用if語句把斷言替換呢?一般而言,if語句是處理邏輯上的可能會發生的錯誤,斷言則用來處理不應該發生的狀況。
當然你如果硬是要用if語句也沒人說你不對,但大量的if語句出現在原始碼中時,會造成**臃腫,降低了可讀性,另外會產生不緊湊**,影響效率。
程式開發初期,碼農們忽視的是程式間呼叫引數的合法性,對這些引數可使用斷言來防止意外,隨著程式進入release版時,可以定義ndebug來讓斷言失效。以下是ndegbu對assert的處理**。
#ifdef ndebug
#define assert(expr) (static_cast(0))
#else
......
#endif
二、如何使用斷言
assert是乙個巨集,c語言原型定義在assert.h中,c++語言原型定義在cassert中,形式為:
void assert(int expression);引數為表示式,如果為0則向stderr列印一條出錯資訊,再呼叫 abort來終止程式。如果為真,則繼續執行其後的語句。
以下以偽**方式講解assert使用方式及注意事項:
// 從堆中動態申請記憶體
char * newbuff(int nsize/*申請記憶體大小*/)
int main()
說明:assert在子函式開始處對引數進行驗證,驗證條件分開,這樣出現問題可以準確定位錯誤,如寫成:
assert(nsize>0 && nszie<=max_buffer_size);這樣就不好了。
assert中不能有改變變數狀態的操作,如:assert(icount++ >= 0);
需要注意的是:assert是巨集,編譯時會在使用處進行**展開,如果程式中大量且頻繁使用,會造成**臃腫,影響效能。
三、c++11中關於斷言的表述
上面例子中的斷言只能在程式執行時起作用。即是動態斷言。有時,程式設計師更希望在編譯期間就能使用斷言,這類斷言稱為靜態斷言,c++11提供了支援。
3.1、動態斷言示例
enum featuresupports;
struct compiler;
int main() ;
......
if( a.spp & c99)
...... }
以上是常見的c**,功能是按位儲存屬性,列舉類中列出了編譯器支援的各種屬性,compiler類成員變數spp,則是用來對屬性的選擇而設定的。主程式中就使用assert對所有的列舉量進行校驗。採用的方法很巧妙,利用了位或的特點來驗證,只要有乙個型別寫錯或漏寫,通過斷言都能發現!
遺憾的是上述程式必須執行後才能發現問題!
c++關於模板的實現中也可以舉出相應的例子:
template
int bit_copy(t& a, u& b)
int main()
3.2、靜態斷言示例
結合assert_static巨集定義和「除0」出錯,c++98實現靜態斷言。
#define assert_static(e) \
do; \
}while(0)
template
int bit_copy(t& a, u& b)
int main()
c++11則提供了static_assert實現了靜態斷言,上面的例子可以改為:
template
int bit_copy(t& a, u& b)
int main()
注意:c++98中定義的是assert_static,c++11中則為static_assert,正好對調!此時c++11編譯要使用-std=c++11開關項。
static_assert是編譯期間進行斷言,使用範圍比assert大,可以用於任何名字空間。如下述**:
static_assert(sizeof(int)==4, "this is 32-bit machine!";
int main()
正由於是編譯期間斷言,所以static_assert表示式中不能有變數,如下則為錯誤**:
int positive(const int a)
此時要求助於assert來完成檢驗!
四、關於斷言的使用原則
最後分享一下《**大全》中對斷言使用的建議:
1、用錯誤處理**處理預期會發生的狀況,用斷言來處理絕不應該發生的狀況;
2、避免把需要執行的**放到斷言中;
3、用斷言來註解並驗證前條件和後條件;
4、對於高健壯性的**,應該先使用斷言再處理錯誤 ;
C 11 靜態斷言static assert
一 assert 在c 中,或中提供了assert巨集 執行期斷言 可以定義ndebug來禁用assert巨集。二 static asser c 11 靜態斷言static assert,編譯期斷言。static assert 常量表示式,提示字串 兩個引數,乙個是斷言表示式,由於是在編譯期間,所以...
C11編譯時斷言static assert
c 11標準新引入的static assert功能可以實現靜態斷言,是乙個非常強大的模板元程式設計工具,配合sfinae特性可以在編譯期發現不符合預期的不合理特化,並且給出自定義的錯誤資訊。1.static assert是 c11 中引入的關鍵字。static assert是 c11 中引入的巨集,...
C 11 基於範圍的for迴圈和靜態斷言
在c 中for迴圈可以使用基於範圍的for迴圈,示例 如下 include using namespace std void test01 int n sizeof arr sizeof arr 0 for int i 0 i n i cout endl for int tmp arr cout e...