程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> assert宏的深入學習

assert宏的深入學習

編輯:C++入門知識

assert宏的原型定義在頭文件assert.h中,它的作用是如果宏後面的條件返回假,則終止程序的執行,該宏會調用__assert_fail函數,這個函數內部會先向stderr輸出錯誤信息,然後調用abort函數來終止程序的執行。

一,assert宏的定義

如下:


[cpp] 
# define assert(expr)                                                   \ 
  ((expr)                                                               \ 
   ? __ASSERT_VOID_CAST (0)                                             \ 
   : __assert_fail (__STRING(expr), __FILE__, __LINE__, __ASSERT_FUNCTION)) 

__assert_fail函數是一個庫導出函數,導出定義如下:

[cpp]
/* This prints an "Assertion failed" message and aborts.  */ 
extern void __assert_fail (__const char *__assertion, __const char *__file, 
                           unsigned int __line, __const char *__function) 
     __THROW __attribute__ ((__noreturn__)); 
注意上面的__attribute__((__noreturn__))定義,這個屬性通知編譯器,該函數從不返回。運行完這個函數程序就退出來了。
二,禁用assert宏


這裡要注意一個宏,這個宏很有用,可以禁用assert宏,是如何做到的呢?

[cpp] 
#ifdef  NDEBUG 
 
# define assert(expr)           (__ASSERT_VOID_CAST (0)) 
 
/* void assert_perror (int errnum);
 
   If NDEBUG is defined, do nothing.  If not, and ERRNUM is not zero, print an
   error message with the error text for ERRNUM and abort.
   (This is a GNU extension.) */ 
 
# ifdef __USE_GNU 
#  define assert_perror(errnum) (__ASSERT_VOID_CAST (0)) 
# endif 
 
#else /* Not NDEBUG.  */ 
所以,就是如果我們自己定義了NDEBUG宏的話,assert就不會工作了,因為__ASSERT_VOID_CAST宏定義如下:
[cpp] 
#if defined __cplusplus && __GNUC_PREREQ (2,95) 
# define __ASSERT_VOID_CAST static_cast<void> 
#else 
# define __ASSERT_VOID_CAST (void) 
#endif 
三,assert宏注意事項

最好使用assert宏檢查一個條件,就是不要用&&或者||操作符,這樣更容易發現是哪個條件出現問題,在需要的時候,多寫幾個assert宏。
不要使用assert進行變量修改,如assert(k++>10),因為我們可能會禁用這個宏,此時,k++是不會執行的,正如上面我們看到的一樣。
assert不是條件過濾。
四,自定義實現ASSERT宏
我們自己可以定義實現ASSERT宏,這樣可以得到更多的錯誤信息,也可以自己定義錯誤行為。
[cpp] 
#ifndef ASSERT 
#define ASSERT(x) \ 
    (void)Assert((x), __FUNCTION__, __FILE__, __LINE__, #x) 
#endif 
Assert實現如下:
[cpp]
inline bool Assert(bool result, const char* function, const char* file, 
                   int line, const char* expression) { 
  if (!result) { 
    Log_Assert(function, file, line, expression); 
    Break(); 
    return false; 
  } 
  return true; 

上面的Log_Assert函數只用於輸出錯誤信息。
Break定義對錯誤處理的行為,該函數定義如下:
[cpp] 
void Break() { 
#if WIN32 
  ::DebugBreak(); 
#elif OSX  // !WIN32 
  ::Debugger(); 
#else // !OSX && !WIN32 
#if _DEBUG_HAVE_BACKTRACE 
  OutputTrace(); 
#endif 
  abort(); 
#endif // !OSX && !WIN32 

DebugBreak是一個VC的庫函數,可以對進程附加調試信息,還可以加斷點什麼的,其實就是我們有時會遇到的問我們是否要調試,如果我們選擇是的話,就會啟動一個開發環境,打開調試器。
最好的話,實現ASSERT時,啟用命名空間,這樣就更容易控制這個宏了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved