你的位置:首页 > 操作系统

[操作系统]可变参数宏(DEBUG)


之前一直是到处写printf来打印调试信息,不需要是还得一个一个注释掉.之后上网查询发现有很多方法来进行DEBUG打印,参数可变而且方便一次性开关.

#define DEBUG(fmt,...)    printf (fmt,__VA_ARGS__)        这里的“…”指的是可变参数.

int main() { DEBUG(“hello %d”,10); return 0; }

有时候,有个模块有输出信息,错误信息等.如果想单独打开某一部分,可以如此设计:

 1: #define DRV_DEBUG    1
 2: #define DRV_DEBUG_IN  0x0001
 3: #define DRV_DEBUG_OUT  0x0002
 4: #define DRV_DEBUG_ERR  0x0004
 5: #define DRV_DEBUG_ALL  0xFFFF
 6: #if DRV_DEBUG
 7:   unsigned int drv_flags = DRV_DEBUG_ERR | DRV_DEBUG_OUT;
 8:   #define DRV_PRINT(flag, fmt, …)    \
 9:    do{                 \
 10:      if (drv_flags & flag){      \
 11:         printf(fmt, __VA_ARGS__);} \
 12:      }while(0)
 13: #else
 14: #define DRV_PRINT(fmt,…)
 15: #endif
 

这样,我只要打印OUT和ERR:

 1: void drv_write(char * msg_out)
 2: {
 3: 	DRV_PRINT(DRV_DEBUG_OUT,"%s", msg_out);		//输出
 4: 	DRV_PRINT(DRV_DEBUG_ERR,"%s", msg_out);		//输出
 5: 	DRV_PRINT(DRV_DEBUG_IN,"%s", msg_out);		//不输出
 6: }
进一步,可以设计针对整个系统不同模块的LOG输出控制!TCP/IP协议栈实现Lwip就是这么干的.
但是发现光有printf还不够,虽然调试信息是出来了,但是在这么多的调试信息中并不能一下子知道这信息是从哪里打印出来的.所以查到用另一种方法可以将文件名和源码位置都打印出来.
在ANSI C中有这样几个宏
__LINE__:插入当前行号
__FILE__:插入当前原文件名
__DATE__:插入当前编译日期
__TIME__:插入当前编译时间
所以宏就变成这样子了DEBUG(fmt,…)  printf(“FILE:”__FILE__”“,LINE:%d:”fmt”\n”,__LINE__,##__VA_ARGS__)
这里特别注意下##__VA_ARGS__这里的##是很有必要的,因为他的意思是如果没有参数则让预处理器忽略前面一个逗号.上面第一段的写法不加参数是出错的.所以第一段写法必须带参数.
DRV_PRINT(DRV_DEBUG_OUT,“hello world”);		//有问题,需要更改宏定义,在前加上##