Averson的博客专栏

随心而写,不喜勿喷~

《C标准库》—之<assert.h>实现

首先,贴出标准库中<assert.h>的实现源码:


#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(char*)的实现如下:

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

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




全部的代码就在这里了。首先,<assert.h> 里有一个 NDEBUG宏,从assert.h的条件宏中可以看出,如果定义了宏NDEBUG, 那么assert测试宏将等于什么都不做,即就是(void)0,那么我们在自己的程序里就可以关闭assert断言或打开它。如果当前assert不存在,那么#undef指令也没任何副作用,因为总是可以#undef一个名字。但是,如果定义有所改变的话,这个#undef指令还是很有必要的。


  如果没有定义NDEBUG, 它将实现它的截断程序的功能,即就是:如果assert(test)里test为真, 证明程序运行到此处没有错误,否则的话,将错误的信息送给_Assert函数,_Assert函数负责将错误信息的源文件(__FILE__)和所在的行(__LINE__) 输出到标准错误流。


我们具体研究下里面的细节。首先是两个宏:__FILE__和__LINE__     __FILE宏会自己扩展为字符串常量,如果错误来自某个.cpp文件或者.c文件,那么它就等同于"***.cpp" 或"***.c",这个宏很好理解,相对于__FILE__,__LINE__的理解不是很容易。__LINE__这个宏并没有扩展为对应行的字符串,而是变成了一个十进制常量,而_Assert函数的参数指向的是个字符串,所以我们有必要把__LINE__转换为相应的字符串。


对于__LINE__的转换,我们使用了C语言中嵌套宏的方法,来实现将十进制常量转换为对应的字符串。

#define _STR(x) _VAL(x)
#define _VAL(x) #x


就是这两个宏的作用。这两个宏缺一不可。#define  _STR(x)   _VAL(x) 这个宏的作用是将__LINE__替换为对应的实参,即就是它的十进制常量,#define _VAL(x)#x 将它的十进制常量变为一个字符串,这个就是宏中#的作用。


那么,具体的是怎么转换的呢,这里有一条关于嵌套宏的展开规则:


遇到宏名后(1)

检查对应的宏体中是否含有#和##运算符
无——处理宏参数(实参)(2)
遇到宏名,回到(1)
没有遇到,在宏体中用实参字符串替换形式参数,再检查是否遇到宏名(4)

有——不检查宏参数,在宏体中用实参字符串替换形式参数,再检查是否含有宏名(3)
遇到宏名,回到(1)
没有遇到,结束 (5)


对应的#define  _STR(__LINE__)  __VAL(__LINE__), #define  __VAL(__LINE__)  #__LINE__,我们就可以这样理解它具体的展开方式了:


首先,检查#define _STR(__LINE__)__VAL(__LINE__)中是否有#或##运算符,这里没有,好,然后在宏的参数表里也没有遇到宏名,那么在这个宏体中,我们就用__LINE__的十进制常量(假设是10)替换了__LINE__,接下来到了 #define  __VAL(__LINE__)   #__LINE__ ,检查过后,发现这个宏体里存在#运算符,那么我们就不检查宏参数了, 直接将实参10替换为"10"  ,这个就是#10的效果。然后我们再检查宏的参数表里有没有遇到宏名,这里没有遇到,结束。

经过这一番转换,我们就可以得到了__LINE__的十进制常量10对应的字符串“10”, 然后连同其它字符串一块传给了_Assert函数。这也是过渡宏_VAL的存在的原因,存在的作用就是把__LINE__替换为10.



我学习过了这个宏后,对宏里一些用法又有了一些了解,比如:


#x 将x变为"x",即添加双引号;

a##b 将a和b黏结起来,ab,不一定是黏结字符串;

#@x  将x变为'x', 即添加了单引号。 



阅读更多
版权声明:需要转载请私信啦~ https://blog.csdn.net/JY_95/article/details/45260775
个人分类: C
想对作者说点什么? 我来说一句

C 标准库—— assert.h

头文件

lanchunhui lanchunhui

2016-02-27 11:18:09

阅读数:353

assert.h C标准库介绍

C标准库

wulonghua wulonghua

2011-02-19 00:14:00

阅读数:560

没有更多推荐了,返回首页

不良信息举报

《C标准库》—之<assert.h>实现

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭