/* assert example */
#include <stdio.h>
#include <assert.h>
void print_number(int* myInt) {
assert (myInt!=NULL);
printf ("%d/n",*myInt);
}
int main ()
{
int a=10;
int * b = NULL;
int * c = NULL;
b=&a;
print_number (b);
print_number (c);
return 0;
}
In this example, assert is used to abort the program execution if print_number is called with a null pointer as attribute. This happens on the second call to the function, which triggers an assertion failure to signal the bug
在這個定義裏,當定義了預處理符號NDEBUG的時候,斷言是無效的,這意味着assert斷言宏只在你的Debug版本中有效。在Release版本里,assert斷言宏不進行任何計算。由於這個而會引起一些側面效裏
斷言使用方式
斷言可以有兩種形式
1.assert Expression1
2.assert Expression1:Expression2
其中Expression1應該總是一個布爾值,Expression2是斷言失敗時輸出的失敗消息的字符串。如果Expression1爲假,則拋出一個
AssertionError,這是一個錯誤,而不是一個異常,也就是說是一個不可控制異常(unchecked
Exception),AssertionError由於是錯誤,所以可以不捕獲,但不推薦這樣做,因爲那樣會使你的系統進入不穩定狀態。
斷言在默認情況下是關閉的,要在編譯時啓用斷言,需要使用source1.4標記
既javac source1.4 Test.java ,在運行時啓用斷言需要使用 -ea參數 。要在系統類中啓用和禁用斷言可以使用 -esa 和 -dsa參數。
例如:
public class AssertExampleOne{
public AssertExampleOne(){}
public static void main(String args[]){
int x=10;
System.out.println("Testing Assertion that x==100");
assert x=100:"Out assertion failed!";
System.out.println("Test passed!");
}
}
如果編譯時未加 -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;
這個斷言的副作用是因爲它修改了程序中變量的值並且未拋出錯誤,這樣的錯誤如果不細心的檢查是很難發現的。但是同時我們可以根據以上的副作用得到一個有用的特性,根據它來測試斷言是否打開。
public class AssertExampleTwo{
public static void main(String args[]){
boolean isEnable=false;
//...
assert isEnable=true;
if(isEnable==false){
throw new RuntimeException("Assertion shoule be
enable!");
}
}
}
1.可以在預計正常情況下程序不會到達的地方放置斷言 :assert
false
2.斷言可以用於檢查傳遞給私有方法的參數。(對於公有方法,因爲是提供給外部的接口,所以必須在方法中有相應的參數檢驗才能保證代碼的健壯性)
3.使用斷言測試方法執行的前置條件和後置條件
4.使用斷言檢查類的不變狀態,確保任何情況下,某個變量的狀態必須滿足。(如age屬性應大於0小於某個合適值)
編輯本段什麼地方不要使用斷言
斷言語句不是永遠會執行,可以屏蔽也可以啓用
因此:
1.不要使用斷言作爲公共方法的參數檢查,公共方法的參數永遠都要執行
2.斷言語句不可以有任何邊界效應,不要使用斷言語句去修改變量和改變方法的返回值
宏名: assert
功 能: 測試一個條件並可能使程序終止
用 法: void assert(int test);
程序例:
#include <
assert.h>
#include <stdio.h>
#include <stdlib.h>
struct ITEM {
int key;
int value;
};
/* add item to list, make sure list is not null */
void additem(struct ITEM *itemptr) {
assert(itemptr != NULL);
/* add item to list */
}
int main(void)
{
additem(NULL);
return 0;
}
assert() 宏用法
assert宏的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程序執行,原型定義:
#include <assert.h>
void assert( int expression );
assert的作用是先計算表達式 expression
,如果其值爲假(即爲0),那麼它先向stderr打印一條出錯信息,
然後通過調用 abort 來終止程序運行。
請看下面的程序清單badptr.c:
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
int main( void )
{
FILE *fp;
fp = fopen( "test.txt", "w"
);//以可寫的方式打開一個文件,如果不存在就創建一個同名文件
assert( fp ); //所以這裏不會出錯
fclose( fp );
fp = fopen( "noexitfile.txt", "r"
);//以只讀的方式打開一個文件,如果不存在就打開文件失敗
assert( fp ); //所以這裏出錯
fclose( fp ); //程序永遠都執行不到這裏來
return 0;
}
[root@localhost error_process]# gcc badptr.c
[root@localhost error_process]# ./a.out
a.out: badptr.c:14: main: Assertion `fp' failed.
已放棄
使用assert的缺點是,頻繁的調用會極大的影響程序的性能,增加額外的開銷。
在調試結束後,可以通過在包含#include <assert.h>的語句之前插入 #define
NDEBUG 來禁用assert調用,示例代碼如下:
#include <stdio.h>
#define NDEBUG
#include <assert.h>
用法總結與注意事項:
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不能代替條件過濾
注意:當對於浮點數:
#include<assert.h>
// float pi=3.14;
// assert(pi=3.14); //
float pi=3.14
f;
assert (pi=3.14
f);
---------------------------------------------------------
在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;
}