参考链接:1 ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))
2 对C语言中va_list,va_start,va_arg和va_end的一点理解
3 C 库宏 - va_start()
4 vsnprintf函数用法
5 C,C++宏中#、##和__VA_ARGS__的理解
6 C语言中函数参数的省略号
7 函数参数带省略号的用法
8 调试技巧——宏定义开关和printf
9 怎样写参数个数可变的宏
10 __VA_ARGS__用法
example 1:
main.c
#include
#include "Debug.h"
int main(int argc, char *argv[])
{
int data = 999;
printDebugMsg("TestProgram", "data= %d", data);
printf("Hello C-Free!\n");
return 0;
}
Debug.h
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
#define _DEBUG
#ifdef _DEBUG
//#define DEBUG_TO_FILE
#ifdef DEBUG_TO_FILE
//调试信息输出到以下文件
#define DEBUG_FILE "..//tmp//debugmsg.txt"
//调试信息的缓冲长度
#define DEBUG_BUFFER_MAX 4096
//将调试信息输出到文件中
#define printDebugMsg(moduleName, format, ...) {\
char buffer[DEBUG_BUFFER_MAX+1] = {0};\
snprintf(buffer, DEBUG_BUFFER_MAX,\
"[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__);\
FILE* fd = fopen(DEBUG_FILE, "a");\
if(fd != NULL){\
fwrite(buffer, strlen(buffer), 1, fd);\
fflush(fd);\
fclose(fd);\
}\
}
#else //#ifndef DEBUG_TO_FILE
//将调试信息输出到终端
#define printDebugMsg(moduleName, format, ...)\
printf("[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__);
#endif //end for #ifdef DEBUG_TO_FILE
#else
//发行版本,什么也不做
#define printDebugMsg(moduleName, format, ...)
#endif //end for #ifdef _DEBUG
/*--------------------Private Function------------------------*/
extern void printfDebugMsg(const char* format, ...);
#ifdef __cplusplus
}
#endif
#endif /*__DEBUG_H__*/
/******************* (C) COPYRIGHT 2018 *****END OF FILE****/
Debug.c
#include "Debug.h"
#define DEBUG_BUFFER_MAX 4096
/*
只有支持C99规范的gcc编译器才有__VA_ARGS__这个宏,
如果不是gcc编译器,或者所用的gcc编译器版本不支持__VA_ARGS__宏怎么办
*/
void printfDebugMsg( const char* format, ...)
{
char buffer[DEBUG_BUFFER_MAX + 1]={0};
va_list arg;
va_start (arg, format);
vsnprintf(buffer, DEBUG_BUFFER_MAX, format, arg);
va_end (arg);
printf( "%s", buffer );
}
测试结果:
example 2:
debug.h
#ifndef __DEBUG_H__
#define __DEBUG_H__
#ifdef __cplusplus
extern "C" {
#endif
#include
#include
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define _DEBUG
#ifdef _DEBUG
//#define DEBUG_TO_FILE
#ifdef DEBUG_TO_FILE
//调试信息输出到以下文件
#define DEBUG_FILE "..//tmp//debugmsg.txt"
//调试信息的缓冲长度
#define DEBUG_BUFFER_MAX 4096
//将调试信息输出到文件中
#define printDebugMsg(moduleName, format, ...) {\
char buffer[DEBUG_BUFFER_MAX+1] = {0};\
snprintf(buffer, DEBUG_BUFFER_MAX,\
"[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__);\
FILE* fd = fopen(DEBUG_FILE, "a");\
if(fd != NULL){\
fwrite(buffer, strlen(buffer), 1, fd);\
fflush(fd);\
fclose(fd);\
}\
}
#else //#ifndef DEBUG_TO_FILE
//将调试信息输出到终端
#define printDebugMsg(moduleName, format, ...)\
printf("[%s] "format" File:%s, Line:%d\n", moduleName, ##__VA_ARGS__, __FILE__, __LINE__);
#endif //end for #ifdef DEBUG_TO_FILE
//#define DEBUG(...) printf(__VA_ARGS__)
//#define DEBUG(format, ...) printf (format, ##__VA_ARGS__)
#define DEBUG(format,...) printf("FILE: "__FILE__",LINE: %05d: "format"\n", __LINE__, ##__VA_ARGS__)
#else
//发行版本,什么也不做
#define printDebugMsg(moduleName, format, ...)
//#define DEBUG(...)
#define DEBUG(format, ...)
#endif //end for #ifdef _DEBUG
/* Private define ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#define USE_FULL_ASSERT
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function which reports
* the name of the source file and the source line number of the call
* that failed. If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
/*--------------------Private Function------------------------*/
extern void printfDebugMsg(const char* format, ...);
#ifdef __cplusplus
}
#endif
#endif /*__DEBUG_H__*/
/******************* (C) COPYRIGHT 2018 *****END OF FILE****/
debug.c
#include "Debug.h"
#define DEBUG_BUFFER_MAX 4096
/*
只有支持C99规范的gcc编译器才有__VA_ARGS__这个宏,
如果不是gcc编译器,或者所用的gcc编译器版本不支持__VA_ARGS__宏怎么办
*/
void printfDebugMsg( const char* format, ...)
{
char buffer[DEBUG_BUFFER_MAX + 1]={0};
va_list arg;
va_start (arg, format);
vsnprintf(buffer, DEBUG_BUFFER_MAX, format, arg);
va_end (arg);
printf( "%s", buffer );
}
void assert_failed(uint8_t* file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %d\r\n", file, line);
while (1)
{}
}
main.c
#include
#include
#include "Debug.h"
typedef struct
{
void (*reqCmdCall)(uint8_t);
//FPGA_ACK_PACKAGE fpgaAck;
} FPGA_REQCMD_ACKDATA;
typedef struct fileName
{
char min[3];
char hour[3];
char date[3];
char datehourmin[9];
char Month[3];
char Year[5];
}FILE_NEME_TypeDef;
FILE_NEME_TypeDef tFileName;
void regCmdCallTest(uint8_t data)
{
printf("RegCmdCall Test: data = %d\r\n", data);
}
struct tm* GetCurrentTime(FILE_NEME_TypeDef *INFO)
{
time_t timep;
unsigned int Year = 0;
char str[100]={0};
char *pstr = &str;
struct tm *p;
time(&timep); //返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位
Year = 1970+timep/365/24/60/60;
DEBUG("now Year is %d\r\n", Year);
DEBUG("now time is %s %s\r\n",__TIME__, __DATE__);
pstr = ctime(&timep); //返回一个表示当地时间的字符串,当地时间是基于参数 timer
DEBUG("now time is %s\r\n", pstr);
p = gmtime(&timep);
DEBUG("%d\n",p->tm_sec); /*获取当前秒*/
DEBUG("%d\n",p->tm_min); /*获取当前分*/
DEBUG("%d\n",8+p->tm_hour);/*获取当前时,这里获取西方的时间,刚好相差八个小时*/
DEBUG("%d\n",p->tm_mday);/*获取当前月份日数,范围是1-31*/
DEBUG("%d\n",1+p->tm_mon);/*获取当前月份,范围是0-11,所以要加1*/
DEBUG("%d\n",1900+p->tm_year);/*获取当前年份,从1900开始,所以要加1900*/
DEBUG("%d\n",p->tm_yday); /*从今年1月1日算起至今的天数,范围为0-365*/
itoa(p->tm_min, INFO->min, 10);
DEBUG("INFO->min is %s: \r\n", INFO->min);
itoa(p->tm_hour+8, INFO->hour, 10);
DEBUG("INFO->hour is %s: \r\n", INFO->hour);
itoa(p->tm_mday, INFO->date, 10);
DEBUG("INFO->date is %s: \r\n", INFO->date);
itoa(p->tm_mday*10000 + (p->tm_hour+8)*100 + (p->tm_min), INFO->datehourmin, 10);
DEBUG("INFO->datehourmin is %s: \r\n", INFO->datehourmin);
itoa(p->tm_mon+1, INFO->Month, 10);
DEBUG("INFO->Month is %s: \r\n", INFO->Month);
itoa(p->tm_year+1900, INFO->Year, 10);
DEBUG("INFO->Year is %s: \r\n", INFO->Year);
return p;
}
char* CreateLogmsgFilePath(FILE_NEME_TypeDef *INFO, char** pPath)
{
int index = 0, len = 0;
char path[100] = {"\0"};
char temp[20] = {"\0"};
GetCurrentTime(&tFileName);
strcpy(temp, "..\\msglog\\");
index = strlen(temp);
memcpy(path, temp, index);
memcpy(path+index, tFileName.Year, strlen(tFileName.Year));
index += strlen(tFileName.Year);
memcpy(path+index, "\\", strlen("\\"));
index += strlen("\\");
memcpy(path+index, tFileName.Month, strlen(tFileName.Month));
index += strlen(tFileName.Month);
memcpy(path+index, "\\debugmsg", strlen("\\debugmsg"));
index += strlen("\\debugmsg");
memcpy(path+index, tFileName.datehourmin, strlen(tFileName.datehourmin));
index += strlen(tFileName.datehourmin);
memcpy(path+index, ".txt", strlen(".txt"));
index += strlen(".txt");
memcpy(*pPath, path, index+1);
DEBUG("path = %s\r\n", path);
DEBUG("pPath = %s\r\n", *pPath);
return path;
}
/*
小端转大端
*/
void endianConvert(void* mem, unsigned char len)
{
uint8_t* p = mem;
uint8_t i;
uint8_t temp;
for (i=0; i