在项目开发过程中,我们常常需要打印日志,比如:文件,函数,行数,编译时间等,这样方便我们调试,提升效率。但是在发布阶段,我们要去掉这些调试日志,这样我们要怎么做呢?
1.通过编译器的内置宏变量,对printf 库函数进行封装,变成自己的调试函数。
2.通过条件编译,去掉调试日志。
__FILE__
、__LINE__
、__FUNCTION__
这三个宏是编译器内置宏定义,分别代表调试信息所在文件、行号、函数。
除此之外,常用的宏还有:__DATE__
、__TIME__
,分别代表当前的编译日期与时间。
#define DBG_PRINTF(fmt, args...) \ 用法和printf一样。 利用条件编译进行关闭 #define DEBUG 1 这中情况,就是利用条件编译,如果,没有定义DEBUG变量,就使DBG_PRINTF定义为空。这样在预处理的时候,就巧妙的去掉了debug日志。 同时,需要注意,DEBUG宏有没有在其他地方定义,会不会出现重复定义?这一点也需要注意。 注意到 printf(fmt, ##args); 了吗? 其中:##符号是为了处理args不代表任何参数的情况。如果: 当不加##符号时: DBG_PRINTF("Hello world"); 第二条语句会转化为:printf("Hello world\n", ); 当加##符号时: DBG_PRINTF("Hello world"); 第二条语句会转化为:printf("Hello world\n"); 前者比或者多了一个逗号,当然不是我们想要的。 例如,如果A是一个宏形参,那么#A就是转换为字符串"A"的形参名。这个过程称为 #define ADD(A,B) printf(#A "+" #B "=%d\n",((A)+(B))) ---> ADD(5,20); ---> 5+20=25 ##运算符可以把两个记号组合成一个记号。例: 四、宏展开 使用编译器,单独执行宏展开的步骤,查看宏展开的结果。 gcc -E main.c -o main.i main.i可以通过文本编辑器打开。
do\
{\
printf("<
printf(fmt, ##args);\
}while(0)
测试:二、关闭debug日志
#if DEBUG
#define DBG_PRINTF(fmt, args...) \
do\
{\
printf("<
printf(fmt, ##args);\
}while(0)
#else
#define DBG_PRINTF(fmt, args...)
#endif三、关于#和##
3.1 #号
#号
作为一个预处理运算符
,可以把记号转换成字符串。字符串化(stringizing)
。以下程序演示这个过程:3.2 ##号