一个简单debug信息输出方法
在软件开发时,经常要在代码关键地方添加必要调试信息跟踪代码执行分支或者参数值,为了调试和软件发布方便,调试代码往往要求做到:
1)在debug时生效,而在发布时为了控制编译产物的大小,往往需要去掉debug代码;
2)可用通过参数控制debug信息的输出等级(类型);
下面通过一个例子,介绍如何在代码中添加debug信息的方法。
首先,先在公共的头文件中定义一个宏,比如:
#ifdef DBG
#define DBG_PRINT(Level, Fmt) \
{ \
if (Level <= DebugLevel) \
{ \
printf Fmt; \
} \
}
#else
/* no debug information */
#define DBG_PRINT(Level, Fmt)
#endif
可以看到,这个宏通过条件编译#ifdef DBG … #else … #endif控制;另外,宏通过参数level,对打印内容进行控制;
然后,在外部的Makefile中,通过Makefile参数CFLAGS 进行控制
EXEC = helloworld
OBJS = helloworld.o
\# If you want to debug app, add following line
CFLAGS += -DDBG
CFLAGS += -I./
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS)
romfs:
$(ROMFSINST) /sbin/$(EXEC)
install:
cp -f $(EXEC) $(INSTALL_DIR)/bin
clean:
rm -f core *~ *.o helloworld*.d
OK,这个debug接口就可以使用了,调用这个接口函数的app中,app的代码中可以增加参数-d,如下:
while(argc > 0)
if (...)
{
...
}
else if (strncmp(argv[0], "-d", 2) == 0)
{
{ argc--; argv++; }
DebugLevel= atoi(argv[0]);
}
然后在命令调用时通过参数-d控制调试信息的类型(等级),比如:
#helloworld -d 2
一般的调试信息等级可以分为:
\#define DEBUG_OFF 0
\#define DEBUG_ERROR 1
\#define DEBUG_WARN 2
\#define DEBUG_TRACE 3
\#define DEBUG_INFO 4
Linux kernel中提供8种打印信息,设计错误信息类型时可以参考,
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#define KERN_ERR "<3>" /* error conditions */
#define KERN_WARNING "<4>" /* warning conditions */
#define KERN_NOTICE "<5>" /* normal but significant */
#define KERN_INFO "<6>" /* informational */
#define KERN_DEBUG "<7>" /* debug-level messages */
另外,对于一些系统调用函数失败,错误码记录在errno中,使用该变量需要包含头文件errno.h,然后通过函数接口:
char *strerror(int errnum);
返回该错误码对应的字符信息。比如,socket编程中使用bind绑定服务器IP和端口,返回出错,代码:
DBG_PRINT(DEBUG_ERROR, ("bind rcv tcp failed, msg = %s!\n", strerror(errno)));
输出结果:
bind rcv tcp failed, msg = Address already in use!