我在C.中创建了一个简单的记录器库。我有三个文件
我的示例文件:
图书馆档案:
我的主记录器功能称为logme
。我将不同的宏定义为包装器以指示不同的日志级别:
例如
在example.c中我调用宏:
int int_arg = 55;
WARN(1, "Warn message with level 1");
WARN(1, "Warn message with level %d", int_arg);
WARN
宏定义在loglib.h
:
#define WARN(LEVEL, ...) \
logme(LEVEL, 8, " <%s:%d> inside %s() -- "__VA_ARGS__, __FILE__, __LINE__, __func__);
最后这里是logme
函数:
void slog(int level, int flag, const char *msg, ...)
{
char string[10000];
bzero(string, sizeof(string));
va_list args;
va_start(args, msg);
vsprintf(string, msg, args);
va_end(args);
// .. do other things
}
当我运行示例文件时,这就是我得到的:
在main()中 - 警告级别为1的消息
分段错误(核心转储)
当我使用格式化字符串调用WARN
时出现分段错误。
分段错误显示在vsprintf(string, msg, args);
我的宏有问题吗?
这是我的lib的make文件:
CFLAGS = -g -O2 -Wall -lpthread
LIB = -lrt
OBJS = loglib.o
LIBINSTALL = /usr/local/lib
HEADINSTALL = /usr/local/include
.c.o:
$(CC) $(CFLAGS) -c $< $(LIB)
libslog.a: $(OBJS)
$(AR) rcs liblog.a $(OBJS)
@echo [-] Syncing static library
sync
install:
@test -d $(LIBINSTALL) || mkdir $(LIBINSTALL)
@test -d $(HEADINSTALL) || mkdir $(HEADINSTALL)
@install -m 0664 liblog.a $(LIBINSTALL)/
@install -m 0664 loglib.h $(HEADINSTALL)/
@echo [-] Done
loglib.o: loglib.h
.PHONY: clean
clean:
$(RM) liblog.a $(OBJS)
答案 0 :(得分:1)
这不起作用,因为您在此处尝试__VA_ARGS__
字符串连接:
#define WARN(LEVEL, ...) \
logme(LEVEL, 8, " <%s:%d> inside %s() -- "__VA_ARGS__, __FILE__, __LINE__, __func__);
这会扰乱您的参数序列:__FILE__
不会与<%s
等一起使用。您必须重新定义WARN()
宏,以便__VA_ARGS__
为最后一个。如果要预先添加所有信息,则必须编写适当的可变参数函数。请注意,__func__
不是字符串文字,它引用相应的字符串。
答案 1 :(得分:0)
点击logme功能时排序不正确。 您可以执行以下操作。
#include <strings.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
void logme(int level, int flag, const char *msg_preamble, const char* file, int line, const char* function, const char* msg, ... )
{
char buffer1[10000];
bzero(buffer1, sizeof(buffer1));
sprintf(buffer1, msg_preamble, file, line, function);
char buffer2[10000];
bzero(buffer2, sizeof(buffer2));
va_list args;
va_start(args, msg);
vsprintf(buffer2, msg, args);
va_end(args);
strcat(buffer1, buffer2);
printf("%s\n", buffer1);
}
#define WARN(LEVEL, ...) \
logme(LEVEL, 8, " <%s:%d> inside %s() -- ", __FILE__, __LINE__, __func__, __VA_ARGS__);
int main(int argc, char** argv)
{
int int_arg = 55;
WARN(1, "Warn message with level 1");
WARN(1, "Warn message with level %d", int_arg);
}
答案 2 :(得分:0)
以下是工作解决方案:
/*
* SOURCE_THROW_LOCATION macro returns string which
* points to the file, as well as, the corresponding line
* of the caller function.
*/
#define LVL1(x) #x
#define LVL2(x) LVL1(x)
#define SOURCE_THROW_LOCATION "<"__FILE__":"LVL2(__LINE__)"> -- "
#define WARN(LEVEL, ...) \
logme(LEVEL, FWARN, SOURCE_THROW_LOCATION __VA_ARGS__);
答案 3 :(得分:0)
参数顺序不正确,因此%s
格式与提供的实际参数不对应,程序调用未定义的行为。
以下是WARN
宏的更正版本:
#define WARN(LEVEL, ...) \
logme(LEVEL, 8, __FILE__, __LINE__, __func__, __VA_ARGS__);
以及相应的logme
函数,使用vsnprintf()
代替vsprintf()
来避免潜在的缓冲区溢出:
void slog(int level, int flag, const char *filename, in lineno,
const char *funcname, const char *msg, ...) {
char string[10000];
int prefix;
va_list args;
// check level, flag..
...
// format the message if needed
prefix = snprintf(string, sizeof string, " <%s:%d> inside %s() -- ",
filename, lineno, funcname);
va_start(args, msg);
vsnprintf(string + prefix, sizeof(string) - prefix, msg, args);
va_end(args);
// do other things
...
}