assert

assert

編程術語
編寫代碼時,我們總是會做出一些假設,斷言就是用于在代碼中捕捉這些假設,可以将斷言看作是異常處理的一種高級形式。斷言表示為一些布爾表達式,程序員相信在程序中的某個特定點該表達式值為真。可以在任何時候啟用和禁用斷言驗證,因此可以在測試時啟用斷言,而在部署時禁用斷言。同樣,程序投入運行後,最終用戶在遇到問題時可以重新起用斷言。
  • 中文名:斷言
  • 外文名:
  • 别名:
  • 英文名:assert
  • 屬于:及物動詞 vt
  • 前置條件斷言:代碼執行之前必須具備的特性
  • 解釋:維護,堅持;主張擁有等
  • 注意:assert是宏,而不是函數
  • 類型:布爾類型

基本解釋

及物動詞 vt.

1.斷言,聲稱[+that][O2]

She asserted her innocence.

她宣稱她是清白的。

He asserted that he was not guilty.

他聲明他無罪。

2.維護,堅持;主張擁有

The boss asserted his authority by punishing his employees.

老闆靠懲罰雇員來維護自己的權威。

3.顯示;确立;聲明,維護,宣稱

C裡用法

使用斷言可以創建更穩定,品質更好且不易于出錯的代碼。當需要在一個值為FALSE時中斷當前操作的話,可以使用斷言。單元測試必須使用斷言(Junit/JunitX)。

除了類型檢查和單元測試外,斷言還提供了一種确定各種特性是否在程序中得到維護的極好的方法。

使用斷言使我們向按契約式設計更近了一步。

斷言特性

前置條件斷言:代碼執行之前必須具備的特性。

後置條件斷言:代碼執行之後必須具備的特性。

前後不變斷言:代碼執行前後不能變化的特性。

java斷言

斷言在默認情況下是關閉的,要在編譯時啟用斷言,需要使用source1.4标記 既javac source1.4 Test.java ,在運行時啟用斷言需要使用 -ea參數 。要在系統類中啟用和禁用斷言可以使用 -esa和 -dsa參數。

例如:

publicclassAssertExampleOne{

publicAssertExampleOne(){}

publicstaticvoidmain(Stringargs[]){

intx=10;

System.out.println("TestingAssertionthatx==100");

assertx==100:"Outassertionfailed!";

System.out.println("Testpassed!");

}

}

如果編譯時未加 -source1.4,則編譯通不過

在執行時未加 -ea 時輸出為

Testing Assertion that x==100

Test passed

jre忽略了斷言的舊代碼,而使用了該參數就會輸出為

Testing Assertion that x==100

Exception in thread "main" java.lang.AssertionError: Out assertion failed!

at AssertExampleOne.main(AssertExampleOne.java:6)

斷言的副作用

由于程序員的問題,斷言的使用可能會帶來副作用 ,例如:

boolean isEnable=false;

//...

assert isEnable=true;

這個斷言的副作用是因為它修改了程序中變量的值并且未抛出錯誤,這樣的錯誤如果不細心的檢查是很難發現的。但是同時我們可以根據以上的副作用得到一個有用的特性,根據它來測試斷言是否打開。

publicclassAssertExampleTwo{

publicstaticvoidmain(Stringargs[]){

booleanisEnable=false;

//...

assertisEnable=true;

if(isEnable==false){

thrownewRuntimeException("Assertionshoulebeenable!");

}

}

}

使用斷言

1.可以在預計正常情況下程序不會到達的地方放置斷言 :assert false。

2.斷言可以用于檢查傳遞給私有方法的參數。(對于公有方法,因為是提供給外部的接口,所以必須在方法中有相應的參數檢驗才能保證代碼的健壯性)。

3.使用斷言測試方法執行的前置條件和後置條件。

4.使用斷言檢查類的不變狀态,确保任何情況下,某個變量的狀态必須滿足。(如age屬性應大于0小于某個合适值)。

不用斷言

斷言語句不是永遠會執行,可以屏蔽也可以啟用

因此:

1.不要使用斷言作為公共方法的參數檢查,公共方法的參數永遠都要執行。

2.斷言語句不可以有任何邊界效應,不要使用斷言語句去修改變量和改變方法的返回值。

C裡的宏

宏名: assert

功 能: 測試一個條件并可能使程序終止

用 法: void assert(int test);

程序例:

#include

#include

#include

structITEM

{

intkey;

intvalue;

};

/*additemtolist,makesurelistisnotnull*/

voidadditem(structITEM*itemptr)

{

assert(itemptr!=NULL);

/*additemtolist*/

}

intmain(void)

{

additem(NULL);

return0;

}

assert() 宏用法

注意:assert是宏,而不是函數。在C的assert.h頭文件中。

assert宏的原型定義在中,其作用是如果它的條件返回錯誤,則終止程序執行,原型定義:

#defineassert(expr)

((expr)

?__ASSERT_VOID_CAST(0)

:__assert_fail(__STRING(expr),__FILE__,__LINE__,__ASSERT_FUNCTION))

/*DefinedInGlibc2.15*/

assert的作用是先計算表達式expr,如果其值為假(即為0),那麼它會打印出來assert的内容和__FILE__, __LINE__, __ASSERT_FUNCTION,然後執行abort()函數使kernel殺掉自己并coredump(是否生成coredump文件,取決于系統配置);否則,assert()無任何作用。宏assert()一般用于确認程序的正常操作,其中表達式構造無錯時才為真值。完成調試後,不必從源代碼中删除assert()語句,因為宏NDEBUG有定義時,宏assert()的定義為空。

請看下面的程序清單badptr.c:

#include

#include

#include

intmain(void){

FILE*fp;

fp=fopen("test.txt","w");//以可寫的方式打開一個文件,如果不存在就創建一個同名文件

assert(fp);//所以這裡不會出錯

fclose(fp);

fp=fopen("noexitfile.txt","r");//以隻讀的方式打開一個文件,如果不存在就打開文件失敗

assert(fp);//所以這裡出錯

fclose(fp);//程序永遠都執行不到這裡來

return0;

}

[root@localhost error_process]# gcc badptr.c

[root@localhost error_process]# ./a.out

a.out: badptr.c:14: main: Assertion `fp' failed.

如果使用動态鍊接libc,那麼除了__FILE__, __LINE__, __ASSERT_FUNCTION會讓目标變的稍稍大了一點,并不會因為多次使用assert()增加目标很多。不過好處也很明顯,就是會在assert的地方會打印出來文件名,行數,和函數名。另外,要注意用assert()的錯誤程度。如果assert()的條件fail了,那麼會調用abort()函數讓kernel殺掉自己,哪怕用戶自己重新注冊了SIGABRT信号的行為(abort()會先向自己發送信号SIGABRT保證用戶的handler正确執行,然後修改SIGABRT信号的行為為默認行為coredump,再次像自己發送SIGABRT,coredump)。

在調試結束後,可以通過在包含#include 的語句之前插入 #define NDEBUG 來禁用assert調用,示例代碼如下:

#include #define NDEBUG#include 

用法總結與注意事項:

1)在函數開始處檢驗傳入參數的合法性

如:

int resetBufferSize(int nNewSize){ //功能:改變緩沖區大小, //參數:nNewSize緩沖區新長度 //返回值:緩沖區當前長度 //說明:保持原信息内容不變 nNewSize<=0表示清除緩沖區 assert(nNewSize >= 0); assert(nNewSize <= MAX_BUFFER_SIZE); ...}

2)每個assert隻檢驗一個條件,因為同時檢驗多個條件時,如果斷言失敗,無法直觀的判斷是哪個條件失敗

/***不好***/assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);/****好****/assert(nOffset >= 0);assert(nOffset+nSize <= m_nInfomationSize);

3)不能使用改變環境的語句,因為assert隻在DEBUG生效,如果這麼做,會使用程序在真正運行時遇到問題

錯誤: assert(i++ < 100)

這是因為如果出錯,比如在執行之前i=100,那麼這條語句就不會執行,那麼i++這條命令就沒有執行。

正确: assert(i < 100)

i++;

4)assert和後面的語句應空一行,以形成邏輯和視覺上的一緻感

5)有的地方,assert不能代替條件過濾

注意:當對于浮點數:

#includefloat pi=3.14f;assert (pi==3.14f);

在switch語句中總是要有default子句來顯示信息(Assert)。

int number = SomeMethod();switch(number){ case 1: Trace.WriteLine("Case 1:"); break; case 2: Trace.WriteLine("Case 2:"); break; default : Debug.Assert(false); break;}

相關詞條

相關搜索

其它詞條