C 11之斷言(影響面廣)

2021-07-25 18:23:04 字數 2441 閱讀 3188

很可笑,我很少用斷言,對斷言的不了解程度與初學者無異。今天翻看了《深入理解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...