在编写嵌入式设备程序的时候,往往需要用printf函数来跟踪程序的运行情况,但当程序越来越大时,printf就用得越多,打印的信息也就多了起来。程序发布之前,我们又往往会把printf去掉。这种做法不仅费时,而且是对工作成果的一种浪费,如果下一次想要查看调试信息的时候,就回不来了。
我们现在就用宏来解决这个问题
//log.h
#ifndef LOG_H #define LOG_H //#define LOG_FILE //以文件的形式输出 #define LOG_PRINT //以printf的形式输出 //如果都不定义,则不输出 #if (defined LOG_FILE) extern char printBuf[100]; void openlog(char *fileName); void addlog(char *log); void closelog(void); #define OPEN_LOG(A) openlog(A) #define ADD_LOG(fmt, args...) do{\ memset(printBuf, 0, sizeof(printBuf));\ sprintf(printBuf,fmt, ## args);\ addlog(printBuf);\ }while(0) #define CLOSE_LOG() closelog() #else #ifdef LOG_PRINT #define OPEN_LOG(A) /*空函数*/ #define ADD_LOG(fmt, args...) printf(fmt, ## args) #define CLOSE_LOG() /*空函数*/ #else #define OPEN_LOG(A) /*空函数*/ #define ADD_LOG(fmt, args...) /*空*/ #define CLOSE_LOG() #endif #endif #endif /* LOG_H */
//log.c #include "log.h" #include <stdio.h> #include <stdlib.h> #include <time.h> #ifdef LOG_FILE FILE *logFd = NULL; struct timeval tv; char printBuf[100]; void openlog(char *fileName){ time_t timep; time (&timep);/*获取时间*/ logFd = fopen(fileName, "at+"); if(logFd == NULL){ perror("fopen"); } gettimeofday(&tv, NULL);/*初始化时间*/ /*记录打开信息*/ fputs("log opened: ",logFd); fputs(asctime(gmtime(&timep)),logFd); } void addlog(char *log){ struct timeval thisTv; if(logFd == NULL) return; time_t timep; gettimeofday(&thisTv,NULL);/*获取当前时间*/ if( (thisTv.tv_sec - tv.tv_sec)>=(60*60) ){/*每小时计录一次时间信息*/ fputs("time: ", logFd); fputs(asctime(gmtime(&timep)),logFd); } fputs(log,logFd);/*输出log*/ } void closelog(void){ fclose(logFd); } #endif
将上面的代码添加到工程当中,调用OPEN_LOG(“file_name”)来初始化,用ADD_LOG()来替代printf。在程序开发的初期阶段,定义LOG_PRINT这个宏开关,这时OPEN_LOG("file_name")在实际编译时会成为空操作,而ADD_LOG则会被替换成printf。在程序开发的测试阶段,定义LOG_FILE这个宏开关,这时OPEN_LOG(“file_name”)就会变成创建用于保存log的文件,而ADD_LOG则会将调试信息保存到"file_name"文件里。在程序完成时,将宏开关LOG_PRINT与LOG_FILE都去掉,这时OPEN_LOG("file_name")与ADD_LOG()都成为了空操作。