在C代码的日常调试或者测试过程中,常常需要通过打印来输出代码运行过程中的一些状态,以便了解程序运行过程中到底进行了什么样的动作,因而在整个项目中将会存在大量日志输出的操作,而正式工程的输出并不需要这些。在发布正式程序时需要屏蔽这些操作,而在调试时又需要打开这些代码。通过宏定义能够快速注释和取消注释,但是会存在大量的判断语句。
本文将通过可变参函数的方式实现这种日志管理,以printf打印输出为例:
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
使用可变参函数,需要包含stdarg.h头文件
在调试测试过程中,不同的情况下可能需要不同的打印输出,创建一个打印等级来控制打印的需求,创建一个宏作为日志打印的选择开关,对日志打印函数作一次封装,对日志打印函数所在位置的函数名和行号进行输出。使用__VA_ARGS__特殊形参表示可变参数的宏,否则vs无法正常传递参数。
#define EM_Log(level,...) EM_LOG(level,__FUNCTION__,__LINE__,__VA_ARGS__)
#define OPEN_LOG 1
typedef enum
{
DEBUG = 0,
WARNING,
ERROR,
}EN_ALMLEVEL_T;
日志打印函数包含等级和打印数据两个输入
void EM_LOG(EN_ALMLEVEL_T level,char * function,int line, char *fmt, ...)
{
#ifdef OPEN_LOG
va_list arg;
va_start(arg, fmt);
char *buff = (char *)malloc((vsnprintf(NULL,0,fmt,arg)+1) * sizeof(char));
vsnprintf(buff, strlen(buff),fmt, arg);
va_end(arg);
if (DEBUG <= level)
{
printf("[%s] [%s %d] %s\n", Get_Alm_Level(level), function, line, buff);
}
#endif // OPEN_LOG
}
定义一个buff用来存储list,使用vsnprintf函数当输出指针为NULL时返回返回list变量占用内存大小。创建一个日志等级的函数获取不同日志等级时对应的字符输出
char * Get_Alm_Level(const int level)
{
if (DEBUG == level)
{
return "debug!";
}
else if (WARNING == level)
{
return "Warning!";
}
else if (ERROR == level)
{
return "error!";
}
}
函数调用即可正常进行日志打印:
void main()
{
char a = 1;
EM_LOG(DEBUG, __FUNCTION__, __LINE__, "%s %s","app_start","note!");
EM_Log(DEBUG, "%s %d", "A =", a);
}
结果如下:
[debug!] [main 63] app_start note!
[debug!] [main 64] A = 1
请按任意键继续. . .
通过OPEN_LOG宏定义实现日志打印选择,通过日志等级设定选择输入想要打印的日志,省去了代码调试和发布之间代码注释和取消注释的工作。