当前位置:编程学习 > C/C++ >>

assert宏的深入学习

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时,启用命名空间,这样就更容易控制这个宏了。

补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,