如何编写一个日志函数或宏,可以将调用者的名称附加到C中的日志输出

时间:2014-08-25 20:22:53

标签: c logging macros

我需要C语言中的日志功能或宏,它应该在Linux中工作,可以接受格式字符串和参数列表,并且可以将调用者的函数名称附加到输出字符串。

这是一个例子。假设日志记录功能(宏)称为smart_log。它看起来像:

smart_log(const char *fmt, ...)

第一个参数fmt是一个格式字符串,就像printf中的格式字符串一样。 fmt之后是一个供给fmt的其他参数列表。

假设一个名为example_function的函数以这种方式调用smart_log:

void example_function() {
    smart_log("try to output number %d\n", 1);
}

然后日志字符串看起来像:

[example_function]: try to output number 1

所以关键是smart_log将调用者函数附加到格式字符串。

我不知道如何在C中实现这一点。我认为可以使用宏来实现这一点。

4 个答案:

答案 0 :(得分:6)

没有可移植的方法让函数在C中知道它的调用者。但是你是对的,宏工作:

#define smart_log(...) ( printf("[%s]: ", __func__) , printf(__VA_ARGS__) )

__func__已定义(C99 / C11 6.4.2.2第1页)

  

就好像紧跟在每个函数定义的左大括号之后的声明

     

static const char __func__[] = "function-name";

     

出现,其中 function-name 是词法封闭函数的名称。


感谢Hagen von Eitzen改善了原来的尝试!

答案 1 :(得分:2)

这是非常依赖于系统/编译器的,因为获取函数名称的确切含义在很大程度上取决于编译器。对于Visual C ++,您可以使用宏__FUNCTION__在编译时获取当前函数名。

为了确保在没有将宏放入smart_log的每次调用的情况下记录正确的函数名,您可以通过宏调用日志函数,以便获取函数名称的宏正确的上下文 - 如果您简单地将宏添加到函数名称,您将始终获得日志记录函数的名称...

所以不要叫这个:

smart_log("log message");

你打电话:

SMART_LOG("log message");

反过来定义为:

#define SMART_LOG(message) smart_log(__FUNCTION__, message)

这是假设您的日志函数将函数名称作为第一个参数,因此调整以适应。

答案 2 :(得分:2)

如果您不想使用宏,可以使用堆栈。 smart_log函数将位于调用它的函数之上。

请参阅How can one grab a stack trace in C?

答案 3 :(得分:1)

定义一个宏 - SMART_LOG - 将__FILE____FUNCTION____LINE__作为参数传递给smart_log。然后,无论何时使用SMART_LOG,它都会自动向smart_log提供调用者的代码位置。但请注意,__FUNCTION__是非标准的,但在GCC中可用(和Visual C,所以我相信),请参阅:https://stackoverflow.com/a/597081/191492)。