使用C

时间:2017-01-22 13:43:55

标签: c macros

我在C.中创建了一个简单的记录器库。我有三个文件

我的示例文件:

  • example.c

图书馆档案:

  • loglib.h
  • loglib.c

我的主记录器功能称为logme。我将不同的宏定义为包装器以指示不同的日志级别:

例如

  • WARN
  • ERROR
  • 等。

在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)

4 个答案:

答案 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
    ...
}