在嵌入式实际的开发中,我们经常会使用printf打印来调试我们的代码,终端查看结果等信息.但是正真的产品发布的时候,我并不希望调试信息被打印出来,这个时候就需要我们屏蔽掉我们用于调试的代码段.一般的做法如下:
1.最容易也是最常用的就是注释掉这些打印信息:
如:
//printf("hello\n");
可想而知如果软件中存在大量的这样的打印语句,注释的工作量太大了,显然不可行.
2.使用预处理指令进行打印调试语句的屏蔽:
如:
#if 0
printf("hello\n");
#endif
当调试的时候将0改为1,产品发布时在改为0,这样显然代码量增多了,更改的工作量也增大了,不可行.
3.同样使用预处理指令指令进行打印调试语句的屏蔽:
如:
#define DEBUG
#ifdef DEBUG
printf("hello\n");
#endif
宏定义只需要在程序中定义一次,需要调试的时候就定义这个宏,不需要就注释掉此宏,发现这种方法调试程序方便的多,但是代码量还是很大.
那么有没有更好的方法来调试我们的打印语句呢?当然有,不过要借助我们的可变宏来做.
以下代码为例说明:
#include <stdio.h>
#define DEBUG
#define DEBUGL
//调试宏
#ifdef DEBUG
#define LOG(format,...) printf(format,##__VA_ARGS__)
#else
#define LOG(format,...)
#endif
//带定位的调试宏
#ifdef DEBUGL
#define LOGL(format,...) printf("<File:"__FILE__",Func:%s"",Line:%d> Pri:"format"\n",__FUNCTION__,__LINE__,##__VA_ARGS__)
#else
#define LOGL(format,...)
#endif
int main(int argc, const char *argv[])
{
LOG("<------------hello---------->\n");
LOGL("Hello");
return 0;
}
首先介绍下普通的调试宏 : 过当DEBUG被定义时,就用LOG(format,…)被printf(format,##VA_ARGS)替换,执行调试打印语句. 未被定义时,LOG(format,…)定义为空,即是不执行任何调试代码.可以看出调试宏为可变宏(参数中有省略号), 预定义的宏 VA_ARGS 是C语言中替换可变参数的宏以表明省略号代表什么. VA_ARGS 前的##是防止无可变参数的时候(如只做普通字符串的打印调试) ,逗号的影响导致的语法错误.这样就可以在调试程序的时候定义DEBUG,发布产品时注释掉定义即可.程序中所有的调试代码也只是一条语句,便捷高效.
下面一种是带定位的调试宏,当发生错误时这样的定位就尤为重要,所有经常会使用这样的宏来调试追踪错误代码,定位错误位置.与普通调试宏相比,只是增加了几个c语言预定的几个宏而已:FILE,FUNCTION,LINE即是我们常用的文件路径名,函数名,行号,通过他们就能唯一定位到调试代码的位置(FILE在c语言中本身就是预定义的文件路径名字符串所以可以那样定义).
有了这样的调试宏,会发现调试代码非常方便,可以根据需要决定调试的打印语句是否需要打印执行,发生错误的时候也可以很方便的定位到错误位置.