您的位置:首页 > 编程语言 > C语言/C++

C语言断言的应用

2016-07-21 21:35 411 查看
一、断言概况
1、断言
(1)在使用C语言编写工程代码时,我们总会对某种假设条件进行检查,断言就是用于在代码中捕捉这些假设,可以将断言看作是异常处理的一种高级形式。
(2)断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。可以在任何时候启用和禁用断言验证,因此可以在测试时启用断言,而在部署时禁用断言。
(3)同样,程序投入运行后,最终用户在遇到问题时可以重新起用断言。它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题可以用断言来进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。
2、一般使用的地方
(1)在函数的入口处,使用断言检查参数的有效性(合法性)。
(2)在编写函数时,要进行反复的考查,并且自问:“我打算做哪些假定?”一旦确定了的假定,就要使用断言对假定进行检查。
(3)可以在预计正常情况下程序不会到达的地方放置断言。(如assert (0);)
(4)使用断言测试方法执行的前置条件和后置条件 。
(5)使用断言检查类的不变状态,确保任何情况下,某个变量的状态必须满足。(如某个变量的变化范围)

二、断言的使用方式
1、使用库函数中的断言
(1)assert宏的原型定义在<assert.h>中,其作用是先计算表达式expression,如果expression的值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用库函数abort()来终止程序运行。
(2)例子
#include <stdio.h>
#include <assert.h>
typedef unsigned char uint8_t;
typedef unsigned long uint32_t;
int main( void )
{
uint8_t var;
var = 0;
assert( var );
return 0;
}


如图所示,运行到assert的时候,因为表达式中的结果为0,所以执行assert内部的语句,打印出错表达式,并且定位出错的文件位置以及出错行数,最后调用abort()函数,终止程序。
如果我把assert( var )改成assert( var == 1 ),则打印出来的是“Assertion failed: var==1, file E:\……”
(3)禁止断言的方法
在#include<assert.h>的前面加上#define NDEBUG
注意:一定是要在该头文件之前添加#define NDEBUG,在头文件之后添加是不能禁止断言的



2、自定义断言函数
(1)根据库函数assert()所展示的功能,我们也可以自定义一个带参宏,并且灵活处理断言的方式
(2)例子
#include <stdio.h>
typedef unsigned char uint8_t;
typedef unsigned long uint32_t;
#define USE_FULL_ASSERT
#ifdef USE_FULL_ASSERT
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__, __func__))
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif

void assert_failed(uint8_t* file, uint32_t line, uint8_t* func)
{
printf("There is an error in line%d, file name:%s, function name:%s", line, file, func);
abort();
}
int main( void )
{
int var = 0;
assert_param( var );
return 0;
}



(3)禁止断言的方法
  我们可以使用条件编译来选择是否使用断言。
  如果使用断言,就使用#define USE_FULL_ASSERT,那么就会用assert_failed代替assert_param(expr),并且声明assert_failed,然后在该函数中实现断言的功能;否则,用(void)0代替assert_param(expr),表示为空语句。

三、断言与if
1、两者区别
(1)if是在最终发布的版本中真实存在的,用于处理程序运行过程中产生的错误(例如处理用户错误输入),以提高程序的健壮性。
(2)断言用于开发阶段的调试,捕捉不应该发生的非法情况,并迅速定位问题。发布的时候需要把断言去掉。

2、例子
char *clone_string( const char *source )
{
char *result;
assert( source != NULL );
result = ( char* )malloc( strlen(source) + 1 );
if( result != NULL )
{
strcpy( result, source );
assert( strcmp(result, source) == 0 );
}
return result;
}

(1)注意到我对source是否为NULL是用assert检查的,但对result是不是为NULL是用if语句判断的
(2)这是因为在调用代码正确的情况下source必然不为NULL,如果断言失败,说明调用代码中有错误,需要修改;但result作为malloc的返回值则不一定,在malloc代码无误的情况下仍然可能返回NULL——当内存块不足时。
(3)最后又用assert对strcpy的结果进行检查,因为只要代码正确,无论什么情况strcpy应该正常完成复制,它没有malloc那种异常情况存在。

参考网址:
【1】C语言之断言http://blog.csdn.net/wxq1987525/article/details/6639220
【2】用断言好还是用if好http://bbs.csdn.net/topics/390680318
【3】关于C语言的assert(断言)http://blog.csdn.net/engrossment/article/details/8118234
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: