首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 编程语言 > C/C++ > P.J.Plauger版本C标准库实现分析之'assert.h' 2006-07-08
【标  题】:P.J.Plauger版本C标准库实现分析之'assert.h' 2006-07-08
【关键字】:P.J.Plauger,assert.h,2006-07-08
【来  源】:http://www.cublog.cn/u/11781/showart.php?id=161121

P.J.Plauger版本C标准库实现分析之'assert.h' 2006-07-08

I believe that seeing a realistic implementation of the Standard C library can help you better understand how to use it.
                                                                                  -- P.J.Plauger

按照字母序首先我们来看看<assert.h>,这个文件提供的接口功能很简单,但却是我们极其常用的功能-断言机制(如果条件为False,则输出Diagnostics信息,然后Abort)。当然在最终产品中使用断言并不是一种好的方法,不过断言是一种很有用的帮助我们调试程序的好工具。

我们一般在程序的调试版本中使用断言机制,一般用来对Input进行Validation,输出一些Diagnostics信息。如:
assert((idx > 10) && (idx < 100));

<assert.h>中提供一个宏assert,这个宏的功能由另一个宏NDEBUG(标志是否是DEBUG版本)决定。如果NDEBUG宏在你include <assert.h>时没有被定义,这时断言功能开启;否则断言功能关闭。如:

#define NDEBUG
#include <assert.h> /* 此时断言功能关闭 */

你也大可不必在你的各个源文件中控制断言功能的开关,在编译器选项中同样可以定义NDEBUG宏,如gcc -DNDEBUG test.c,当然对于大的project,这些是应该放在Makefile中的,这样的结果就相当于在你所有#include <assert.h>的地方之前定义了NDEBUG宏,也就是说在每个编译单元中,断言功能都是关闭的。

assert宏看起来很简单,但是由于其是C标准库提供的接口,所以在实现的时候需要考虑的更加细致和全面一些。从上面的叙述上来看assert.h文件的结构应该大致如下:
#undef assert
#ifdef NDEBUG
#define assert(test) ((void)0)
#else
#define assert(test) ...
#endif

我们可以很轻松的就拿出一个assert的实现版本:
/* NDEBUG not defined */
#define assert(test) if (!(test))
 fprintf(stderr, "Assertion Failed: %s, file %s, line %dn",
 #test, __FILE__, __LINE__);

那么这个版本的实现可以接受不,答案是不能。原因有以下几点:
1) 这个实现中直接用到了stderr和fprintf,这两个符号都是在<stdio.h>中声明的,但是C标准库头文件基本上都是各自独立的,在<assert.h>中是不会再包含其他头文件的,那么这就要求使用assert的程序自己包含<stdio.h>,这显然不符合一个C标准库的基本要求;
2) assert宏应该最终展开为一个void expression,因为用户很可能在他们的程序中写出像(assert(0 < x), x < y)这样的代码来,而在上面的实现版本中,显然assert展开后不是一个void expression。

我们再来看看P.J.Plauger的实现版本:
/* NDEBUG not defined */
void _Assert(char *);
#define _STR(x) _VAL(x)
#define _VAL(x) #x
 
#define assert(test) (test) ? (void)0
 : _Assert(__FILE__ ":" _STR(__LINE__) " " #test)

/* in xassert.c */
#include <assert.h>
#include <stdio.h>

void _Assert(char *msg) {
 fprintf(stderr, "%s -- assertion failedn", msg);
 abort();
}
 
分析一下这一版本的实现,首先assert宏并没有直接调用任何库输出函数,而是调用了一个自己实现的函数_Assert,把向stderr输出诊断信息的活都交给了_Assert。_STR和_VAL是两个辅助宏,用来将__LINE__字符串化。这里比较难懂的地方就是_Assert(__FILE__ ":" _STR(__LINE__) " " #test)这一句,其实这个也很好理解。看看下面语句的执行结果:
printf("%sn", "Hello" " " "Tony!");
执行上面语句你会看到Hello Tony!,这样一来实际上_Assert(__FILE__ ":" _STR(__LINE__) " " #test)就可以被理解为:
_Assert("THE_FILENAME_STRING" ":" "THE_LINE_STRING" " " "THE_TEST_STRING")

初学者必备:C++经典入门详细教程:【上一篇】
智能指针(smart pointer)::【下一篇】
【相关文章】
  • P.J.Plauger版本C标准库实现分析之'ctype.h'
  • C库函数手册stdlib.h、process.h,assert.h、math.h,io.h...
  • 【随机文章】
  • 重新定位的睿智:读《面向对象的软件再工程模式》
  • 使用AsycnSocket类进行简单双机通讯
  • C#与JAVA
  • net环境下的程序破解一例(2)
  • AlgoLab PtVector的破解及注册机的编写(2)
  • oracle9i在linux9下的安装
  • 4口无线宽带/窄带路由器
  • SCO UNIX快速入门(增补版)
  • 时钟小程序 v 1.0
  • TEW-224UB USB适配器
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 软讯网络 All Rigths Reserved.