首页 > CLucene, 程序人生 > CLucene源码剖析(一) 调试信息的输出

CLucene源码剖析(一) 调试信息的输出

在写比较大型的项目的时候,如何使程序的调试信息能更加方便,优雅的显示出来,也是一件比较好玩的事。最好的效果就是,我在写程序的时候,调试信息越详细越好,而我写完程序,调试完成后,不用再去注释大篇的调试信息,能通过一个较小的改动就把程序中的调试信息去掉,这样就会避免应注释而可能引入新的bug,同时也节省了体力呀!
CLucene是Lucene的C++版本,是老外写的,剖除搜索引擎相关的技术,仅从代码层次来说,其代码质量是不错的,里面有很多值得我学习的地方。打算有空的时候好好研读一下CLucene,一方面学习老外的编程技巧,一方面学习搜索引擎技术。关于这个学习,我希望自己能够坚持下来,也希望在学习的过程中能与感兴趣的朋友一起探讨。今天先从程序的调试信息的输出谈起,以后每学习一部分,我都会将自己的心得记录下来。
CLucene中采用了条件宏方式来输出调试信息,下面是CLucene中定义的几个宏:

1
2
3
4
5
#define CND_PRECONDITION(cond,usermessage)  CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_PRECONDITION,usermessage)
#define CND_CONDITION(cond,usermessage)     CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_CONDITION,usermessage)
#define CND_WARNING(cond,usermessage)       CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_WARNING,usermessage)
#define CND_MESSAGE(cond,usermessage)       CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_MESSAGE,usermessage)
#define CND_DEBUGMESSAGE(usermessage)       CND__MESSAGE(__FILE__,__LINE__,CND_STR_DEBUGMESSAGE,usermessage)

在上面的宏中,CND_PRECONDITION和CND_CONDITION在实现上基本上是一致的,只不过CND_PRECONDITION用来判断前提条件是否满足,CND_CONDITION用来判断过程或结果中的条件是否满足。CND_MESSAGE用来输出条件信息,CND_WARNING用来输出我条件警告信息,CND_DEBUGMESSAGE用来输出调试信息。
下面是上述几个宏的实现过程中用到的另外几个宏:

1
2
3
4
#define CND__EXIT(file,line,title,mes2)                {__cnd_FormatDebug(file,line,title,mes2,1);}
#define CND__EXITCONDITION(cond,file,line,title,mes2)  {if(!(cond)){__cnd_FormatDebug(file,line,title,mes2,1);}}
#define CND__CONDITION(cond,file,line,title,mes2)      {if(!(cond)){__cnd_FormatDebug(file,line,title,mes2,0);}}
#define CND__MESSAGE(file,line,title,mes2)             {__cnd_FormatDebug(file,line,title,mes2,0);}

上面的宏也只是对最终实现函数的又一层包装,要真正了解内幕,还是要看实现函数的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#define __CND_STR_PRECONDITION    "PRECONDITION"
#define __CND_STR_CONDITION       "CONDITION"
#define __CND_STR_WARNING         "WARNING"
#define __CND_STR_MESSAGE         "MESSAGE"
#define __CND_STR_DEBUGMESSAGE    "DEBUG MESSAGE"
#define __CND_STR_EXIT            "EXIT"
 
#ifndef _CND_DEBUG_DONTIMPLEMENT_OUTDEBUG
void _Cnd_OutDebug( const char* FormattedMsg, const char* StrTitle,
                 const char* File, int32_t Line, int32_t Title,
                 const char* Mes2, int32_t fatal ){
	#ifdef __WINDOWS_H
			/*Display a standard messagebox*/
 			MessageBox(NULL, FormattedMsg, StrTitle, (fatal==1 ? MB_ICONSTOP:MB_ICONEXCLAMATION) | MB_OK | MB_TASKMODAL);
	#else
			printf("%s\n",FormattedMsg);
	#endif
 
	#if defined(_CND_DEBUG_WARN_DEBUGGER) /*attempt to signal windows debugger*/
			OutputDebugString(FormattedMsg);
			DebugBreak(); /*Position debugger just before exit program*/
	#endif
 
	if ( fatal )
		debugFatalExit(1);
}
#endif
 
void __cnd_FormatDebug( const char* File, int32_t Line,
                                   int32_t Title, const char* Mes2, int32_t fatal ) {
	char M[512];
    char* StrTitle = NULL;
 
	if( Mes2 )
		_snprintf(M,512,"file:%s line:%d\n%s",File,Line,Mes2);
	else
		_snprintf(M,512,"file:%s line:%d",File,Line);
 
    /*Determine which title to use*/
    switch( Title ) {
        case CND_STR_PRECONDITION: {
            StrTitle = __CND_STR_PRECONDITION;
            break;
            }
        case CND_STR_CONDITION: {
            StrTitle = __CND_STR_CONDITION;
            break;
            }
        case CND_STR_WARNING: {
            StrTitle = __CND_STR_WARNING;
            break;
            }
        case CND_STR_MESSAGE: {
	        StrTitle = __CND_STR_MESSAGE;
            break;
            }
        case CND_STR_DEBUGMESSAGE: {
            StrTitle = __CND_STR_DEBUGMESSAGE;
            break;
            }
        case CND_STR_EXIT: {
            StrTitle = __CND_STR_EXIT;
            break;
            }
        default:
            break;
        }/*switch*/
 
	_Cnd_OutDebug(M, StrTitle, File, Line, Title, Mes2, fatal);
}

在上面的实现函数中, _Cnd_FormatDebug是对输出信息格式化的一层包装,真正的实现在_Cnd_OutDebug中。在该函数中如果定义了__WINDOWS_H,调试信息将以消息窗口的方式弹出,否则,直接printf。另外,如果定义了_CND_DEBUG_WARN_DEBUGGER, 调试信息将在调试控制台输出。如果该信息是CND_PRECONDITION或CND_CONDITION的话,程序还会调用exit而退出。

通过上面的条件宏的包装,在调试的时候,可以把调试信息优雅地输出来。如何在调试完成后把这些调试信息去掉呢,可以通过一个宏,把上述条件宏的实现重新定义过,这这些宏的实现定义为空,就可以了,这样就达到了避免大规模注释代码的工作!

  1. 2009年5月29日05:34 | #1

    Thanks for posting, I very much liked your newest post. I think you should post more frequently, you obviously have natural ability for blogging!

    • 2009年5月29日10:15 | #2

      en, I will try my best to post more, thanks for your appreciation! And I hope you can give more opionion about my future post:)

  2. 2009年5月29日10:33 | #3

    Thanks for posting, I very much liked your newest post. I think you should post more frequently, you obviously have talent for blogging!

  1. 本文目前尚无任何 trackbacks 和 pingbacks.
您必须在 登录 后才能发布评论.