为了兼容多种情况的log记录,写了一个参数比较多log记录函数宏。在应用时,又不想多定义一个变量,把结构体指针直接写在参数里,代码如下。
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#define LOG_LEN_MAX 128
#define LOG_PARA1 1
#define LOG_PARA2 2
#define VAL_TEST 3
typedef struct {
int para1;
int para2;
} LogPara;
#define LOG_TRACE(para, fmt, ...) LogTrace(__FILE__, __LINE__, para, fmt, ##__VA_ARGS__)
int LogTrace(const char *file, int line, LogPara *para, const char *fmt, ...)
{
char logStr[LOG_LEN_MAX] = {0};
sprintf(logStr, "para %d %d, File: %s, Line: %d info: ", para->para1, para->para2, file, line);
va_list args;
va_start(args, fmt);
vsprintf(logStr + strlen(logStr), fmt, args);
va_end(args);
printf("%s \n", logStr);
return 0;
}
int main()
{
int val = VAL_TEST;
LOG_TRACE(&(LogPara){LOG_PARA1, LOG_PARA2}, "val is %d", val);
return 0;
}
结果编译失败,原因时参数太少了。
从定义上看,参数数量没有问题,因为涉及宏展开,因此直接看预处理后的代码,命令和代码片段如下。
int main()
{
int val = 3;
LogTrace(&(LogPara){1, "macro.c", 37, 2}, "val is %d", val);
return 0;
}
文件名和行数的宏直接插进结构体里面去了,从几次实验的结果看,所有的宏参数的位置都是按“,”的位置来插入的,__FILE__前面只有一个逗号,因此展开后插入到了第一个“,”后面。
解决的方法也比较简单,要么把结构体指针放在所有结构体外的宏参数的后面,要么加个括号,如下两种。
结构体放到后面
#define LOG_TRACE(para, fmt, ...) LogTrace(__FILE__, __LINE__, para, fmt, ##__VA_ARGS__)
加个括号
int main()
{
int val = VAL_TEST;
LOG_TRACE((&(LogPara){LOG_PARA1, LOG_PARA2}), "val is %d", val);
return 0;
}
GCC的代码没有研究过,看了一会也没看懂,如果有比较熟悉的大神也帮忙看看处理逻辑。个人认为都可以算GCC的小BUG了。
gitcode链接: