浅谈---assert

我们知道头文件<assert.h>唯一的目的就是提供宏assert的定义。让我们在程序“不可能“”出现的问题的地方使用这个宏进行断言。如果一处断言被证明非真,我们希望程序在标准错误流中输出一条适当的提示信息。并且使程序异常终止。

“不可能” 就是不应该发生的事情,发生了。例如,太阳都是从西边升起的,突然有一天太阳从西边升起了,我们便可以认为,不可能的事情发生了。

在编写代码时,使用断言代码会变得更简单,但是有之而引发的问题,其实还是比较严重,前面说到,断言是用来断言程序“不可能”出现问题的地方使用,若这个问题出现了,断言成功,但这不是编写产品代码的最好方式,让以后需要面向用户的东西,突然中止,这显然不是什么明智的选择。

但这个对编写代码的人员来说,却是十分方便的,可以很快速的找到问题所在。 那么,如何在程序写好以后如何关闭断言,C标准库中给我们提供了十分方便的操作。 使用宏定义 NDEBUG ,至于这里为什么使用NDEBUG 这里,目前我还不是很清楚。但是他的作用是毋庸置疑的。

//关闭断言
#define NDEBUG  // 让assert不起作用
#include<assert.h>
//打开断言
#undef  NDEBUG//让assert起作用 
#include <assert.h>
这里值得注意的是,即使宏NDEBUG已经被定义了。我们仍然可以安全地定义它。这是一个 良性的重定义
这里简单说一下良性重定义的含义:在一个翻译单元内包含这样的宏定义的多个实例不会造成任何损失。在标准C中允许这样的宏的良性重定义。具有相同宏名的两个定义必须具有相同的记号序列。它们只能是记号之间的空白不同(这里的空白指空格符和制表符)。没有必要阻止包含两个符合这样情况的定义。
但是,你必须在多个地方提供相同的定义。这是一个比较麻烦的维护问题。 这里提供两种解决办法:
1.在多个地方编写相同的定义。定义改变时,就要找出这个定义的所有实例。
2.把定义 放在一个独立的头文件中,给这个文件起一个不会和程序员创建的文件名冲突的名字。在每个用到该定义的头文件中包含这个头文件
在大多数情况下,建议选择第二种,因为它简化了使库适用于不同的编译器所做的工作。(这里特殊情况,我还没有想到。)

下面我们来看一下<assert.h>的实现
为了对NDEBUG做出正确的回应,该头文件一定要有一个总体结构:

#undef assert   /*remove existing defintion*/
#ifdef NDEBUG
#define assert (test) ((void) 0) //passive form
#else
#define assert(test)....  //active form
#endif

如果当前的宏assert的定义不存在,那么开头的#undef 预处理指令就不会有任何副作用。总是可以#undef 一个名字,不论它是不是被定义为一个宏,(这里可以把它看做是良性取消定义)但是,如果定义可能改变的话,这条处理指令还是很有必要的。

这里简单说一下#undef命令。
#undef name 

这个命令使预处理器忘记name(这里仅仅指的是宏名)的所有宏定义。取消一个当前未定义宏的定义并不是错误。当一个名称被取消定义之后,就可以向他提供一个全新的定义(使用#define),而不会产生任何错误。在#undef命令内部,并不会执行宏替换。

下面让我们看几个例子,来理解一下

#define NULL 0
#define NULL                              0 
#define f(x) x+1
#define f(Y) Y+1
这里NULL 在进行重定义的时候是允许的,但是f在进行重定义的时候,给了一个警告,说 f 是被定义过了 的。在 #define f(x) x+1 后面加上一句 #undef f 是可以进行定义的。

当我们无法知道是否存在以前的定义的时候,我们可以用 #ifdef 命令来测试是否存在一个现有的定义,已避免对它进行重定义。

#ifdef name 
#ifndef  name 
#ifdef 如果name已经被定义为一个预处理器宏,相当于#if 1

#ifndef 如果name 未被定义时,相当于 #if 1 

 

/* assert.h standard header*/
#undef assert

#ifdef NDEBUG
	#define	assert(test)	((void) 0)
#else
        void  _Assert(char *)
        #define _STR(x)  _VAL(x)
        #define _VAL(x) #x
        #define assert(test)  ((test) ? (void) 0 : _Assert (_FILE_":"_STR(_LINE_)"" #test))
#endif
/* _Assert function */
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>

void _Assert(char *mesg)
{
       fputs(mesg,stderr);
       fputs(" -- assertion failed\n", stderr);
       abort();
}



未完待续。。。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值