c語言——面試之assert斷言使用

查看vs 2013assert定義,如下:
#ifdef NDEBUG

#define assert(_Expression)     ((void)0)

#else  /* NDEBUG */

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */

_CRTIMP void __cdecl _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);

#ifdef __cplusplus
}
#endif  /* __cplusplus */

#define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )

#endif  /* NDEBUG */
assert宏的原型定義在<assert.h>中,其作用是如果它的條件返回錯誤,則終止程序執行,
  1. 原型定義:
  ● #include <assert.h>
  ● void assert( int expression );
頭文件定義了assert宏,引用了NDEBUG,後者未定義在該頭文件內
2 代碼解釋:
     #ifdef NDEBUG
     #define assert(_Expression)     ((void)0)
當調試完成後,如果定義了NDEBUG,關閉斷言,優化生成的代碼

assert的宏定義

代碼如下:

#define assert(_Expression) (void)( (!!(_Expression)) || 
                                     (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
_Expresssion若爲false,則!false=true,!true=false,此時繼續執行||以後的語句,故會打印出出錯信息,終止程序,若_Expression爲true,則!true=false,!false=true,此時不再執行||以後的語句,故不會打印出信息 使用了||運算的截斷 和 !!(_Expression)兩次取否 ,#是把跟在後面的參數轉換成一個字符串

_wassert的宏定義
代碼如下:
 _wassert(_In_z_ const wchar_t * _Message, _In_z_ const wchar_t *_File, _In_ unsigned _Line);

打印出出錯信息調用了abort()函數來終止程序的運行。
問題:
頻繁的調用會極大的影響程序的性能,增加額外的開銷。
在調試結束後,可以通過在包含#include <assert.h>的語句之前插入 #define NDEBUG 來禁用assert調用
#define NDEBUG 
#include <assert.h>


摘自《高質量C/C++編程指南》Page 41-42...
程序一般分爲Debug 版本和Release 版本,Debug 版本用於內部調試,Release 版本發行給用戶使用。
斷言assert 是僅在Debug 版本起作用的宏,它用於檢查“不應該”發生的情況。assert 不是一個倉促拼湊起來的宏。爲了不在程序的Debug 版本和Release 版本引起差別,assert 不應該產生任何副作用。所以assert 不是函數,而是宏。程序員可以把assert看成一個在任何系統狀態下都可以安全使用的無害測試手段。如果程序在 assert 處終止了,並不是說含有該assert 的函數有錯誤,而是調用者出了差錯,assert 可以幫助我們找到發生錯誤的原因。
assert宏注意事項
  • 最好使用assert宏檢查一個條件,就是不要用&&或者||操作符,這樣更容易發現是哪個條件出現問題,在需要的時候,多寫幾個assert宏。
  • 不要使用assert進行變量修改,如assert(k++>10),因爲我們可能會禁用這個宏,此時,k++是不會執行的,正如上面我們看到的一樣。
  • assert不是條件過濾。
自定義實現ASSERT宏
#include<stdio.h>
#define assert(_Expression) (void)( (!!(_Expression)) || _assert(#_Expression, __FILE__, __LINE__), 0 )
void _assert(_Expression, __FILE__, __LINE__)
{
   printf("Assertion Failed: %s, file%s  line %d",_Expression, __FILE__, __LINE__);
    abort();
}

(void)( (!!(_Expression)) || _assert(#_Expression, __FILE__, __LINE__), 0 )
這裏利用了||的短路性質,就是條件爲真,它就不執行後面的了,爲假才執行。如果表達式e爲真,則爲(void)0;表達式e爲假,則調用_assert()這函數
  • #exp會在預處理產生一個字符串.
  • __FILE__,__LINE__,分別表示文件位置和行數。
  • abort():這個函數是一個內部函數,它就是異常中止你運行的程序.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章