编码技巧---调试宏

背景:

在项目开发过程中,我们常常需要打印日志,比如:文件,函数,行数,编译时间等,这样方便我们调试,提升效率。但是在发布阶段,我们要去掉这些调试日志,这样我们要怎么做呢?

1.通过编译器的内置宏变量,对printf 库函数进行封装,变成自己的调试函数。

2.通过条件编译,去掉调试日志。

一、封装自己的函数

__FILE____LINE____FUNCTION__这三个宏是编译器内置宏定义,分别代表调试信息所在文件、行号、函数。

除此之外,常用的宏还有:__DATE____TIME__,分别代表当前的编译日期与时间。

#define DBG_PRINTF(fmt, args...)  \
do\
{\
    printf("<<File:%s  Line:%d  Function:%s>> ", __FILE__, __LINE__, __FUNCTION__);\
    printf(fmt, ##args);\
}while(0) 

测试:

编码技巧---调试宏

 用法和printf一样。

二、关闭debug日志

利用条件编译进行关闭

#define  DEBUG   1  

#if DEBUG
#define DBG_PRINTF(fmt, args...)  \
do\
{\
    printf("<<File:%s  Line:%d  Function:%s>> ", __FILE__, __LINE__, __FUNCTION__);\
    printf(fmt, ##args);\
}while(0)
#else 
#define DBG_PRINTF(fmt, args...) 
#endif

这种情况,就是利用条件编译,如果,没有定义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");

前者比或者多了一个逗号,当然不是我们想要的。

3.1 #号

#号作为一个预处理运算符,可以把记号转换成字符串。

例如,如果A是一个宏形参,那么#A就是转换为字符串"A"的形参名。这个过程称为字符串化(stringizing)。以下程序演示这个过程:

#define ADD(A,B)  printf(#A "+" #B "=%d\n",((A)+(B)))   --->  ADD(5,20);   ---> 5+20=25

即:将一个宏参数转换成字符串。

3.2 ##号

##运算符可以把两个记号组合成一个记号。例:

编码技巧---调试宏

即:将两个或者多个宏参数转换成字符串,之后连接在一起,然后返回。

3.3 #@

#todo

四、宏展开

使用编译器,单独执行宏展开的步骤,查看宏展开的结果。

gcc -E  main.c -o main.i

main.i可以通过文本编辑器打开。

 

 

 

 

上一篇:Go语言之map


下一篇:go map 并发 concurrent 锁