C库宏assert的作用学习

 在pjsip源码中有很多pj_assert的用法,它实际上就是c库assert宏。

#ifndef pj_assert
#   define pj_assert(expr)   assert(expr)
#endif

assert宏的原型定义在<assert.h>中 ,其作用是如果它的条件返回错误,则终止程序执行,linux下原型定义:

#  define assert(expr)							\
    ((expr)								\
     ? __ASSERT_VOID_CAST (0)						\
     : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION))
# else

其他系统定义:

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



#define  ASSERT(f)  \   
do  \   
{  \   
      if  (!(f)  &&  AfxAssertFailedLine(THIS_FILE,  __LINE__))  \   
              AfxDebugBreak();  \   
}  while  (0)  \ 

其作用是先计算表达式expr,为真,就把 0 转化为 void *,相当于什么都没做;

如果其值为假(即为0),执行 __assert_fail 函数,该函数定义:

/* 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__));

即打印出assertion failed消息并aborts终止程序。也有定义如下:

void
__assert_fail (const char *assertion, const char *file, unsigned int line,
    const char *function)
{
    __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"),
    assertion, file, line, function);
}

这里assert_fail_base函数会向stderr输出错误信息:

(void) __fxprintf (NULL, "%s", str);
(void) fflush (stderr);

那么它会打印出来assert的内容和__FILE__, __LINE__, __ASSERT_FUNCTION,即(文件名,行号,函数名),然后执行abort()函数使kernel杀掉自己并coredump(是否生成coredump文件,取决于系统配置);否则,assert()无任何作用。宏assert()一般用于确认程序的正常操作,其中表达式构造无错时才为真值。完成调试后,不必从源代码中删除assert()语句,因为宏NDEBUG有定义时,宏assert()的定义为空。

#ifdef  NDEBUG

# define assert(expr)       (__ASSERT_VOID_CAST (0))

assert只应该出现在debug版本中不应该出现在release版本中,Debug中可以用#undef NDEBUG启用assert,

在调试结束后,如Release版本中关闭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.14f;
assert (pi==3.14f);

//在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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值