斷言的應該是一種編程的常見技巧。我所應用的斷言有兩種,一種是動態斷言,即大家所熟知的C標准庫的assert()宏,一種是C++中的靜態斷言,即在編譯期間檢查。
1)動態斷言:assert宏的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程序執行,原型定義:
- #include <assert.h>
- void assert( int expression );
assert的作用是先計算表達式 expression ,如果其值為假(即為0),那么它先向stderr打印一條出錯信息,然后通過調用 abort 來終止程序運行。
大家要注意是,其中的表達式為假時,會終止程序運行,包括我在內經常會寫錯代碼,斷言一個指針是否為空,往往寫成了
assert(!p);其實應該寫成assert(p);
assert是運行期的判斷,並且會強制終止程序,一般要求只能用於debug版本中,是為了盡可能快的發現問題。尤其在我所從事的電信軟件產品中,assert是要從release版本中去掉。所以一般開發會重新定義assert宏。
2)靜態斷言,在新的C++標准中C++0x中,加了對靜態斷言的支持,引入了新的關鍵字static_assert來表示靜態斷言。使用靜態斷言,我們可以在程序的編譯時期檢測一些條件是否成立。但這個關鍵字太新了,沒有幾個編譯器是支持的(好像VC2008支持,我用VC很少,主要是在linux下C++編程)。於是可以使用C++現有的模板特性來實現靜態斷言的功能。boost中也已有BOOST_STATIC_ASSERT宏的實現,有興趣的同學可以down下來仔細研究一下,它的斷言信息更豐富,下面為我的簡單實現:
- // declare a tempalte class StaticAssert.
- template <bool assertion> struct StaticAssert;
- // only partial specializate parameter's value is true.
- template <> struct StaticAssert<true>
- {
- enum { VALUE = 1 };
- };
- #define STATIC_ASSERT(expression) (void)StaticAssert<expression>::VALUE
原理是,先聲明一個模板類,但后面僅僅偏特化參數值為true的類,而為false的類則一個未定義的類,即是一個未完整的類型,編譯期間無法找到StaticAssert<false>::VALUE類型。舉例如下:
- STATIC_ASSERT(4 == sizeof(long) ); //在 32bit機上OK
- STATIC_ASSERT(4 == sizeof(long) ); //在 64bit機上NG,long為8字節
靜態斷言在編譯時進行處理,不會產生任何運行時刻空間和時間上的開銷,這就使得它比assert宏具有更好的效率。另外比較重要的一個特性是如果斷言失敗,它會產生有意義且充分的診斷信息,幫助程序員快速解決問題。