分享

VC知识库:#define NDEBUG是what?

 黄南山 2017-06-21
主      题: #define NDEBUG是what?
作      者: wjyok_2005
回复次数: 5
发表时间: 2007-1-26 8:39:13
正文内容: 无

回复人: YangTze (得分:2)2007-1-26 8:41:20
就是说 有 NDEBUG 这么个符号定义存在


回复人: wjyok_20052007-1-26 8:43:05
他不是vc6提供的东西么?


回复人: leiallok (得分:4)2007-1-26 8:44:02
Re:#define NDEBUG是what?
按照字母序首先我们来看看<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 %d\n", \
#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 failed\n", msg);
abort();
}
  
分析一下这一版本的实现,首先assert宏并没有直接调用任何库输出函数,而是调用了一个自己实现的函数_Assert,把向stderr输出诊断信息的活都交给了_Assert。_STR和_VAL是两个辅助宏,用来将__LINE__字符串化。这里比较难懂的地方就是_Assert(__FILE__ ":" _STR(__LINE__) " " #test)这一句,其实这个也很好理解。看看下面语句的执行结果:
printf("%s\n", "Hello" " " "Tony!");
执行上面语句你会看到Hello Tony!,这样一来实际上_Assert(__FILE__ ":" _STR(__LINE__) " " #test)就可以被理解为:
_Assert("THE_FILENAME_STRING" ":" "THE_LINE_STRING" " " "THE_TEST_STRING")




回复人: believefym (得分:2)2007-1-26 8:44:31
Re:就是说 有 NDEBUG 这么个符号定义存在
同意,只是存在这么一个宏,但是这个具体的值是不重要的,就可以把它忽略

回复人: yqever (得分:2)2007-1-26 8:44:59
不是吧?

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多