5

我的桌面上运行了一个 linux 应用程序,我想将 syslog() 调用重定向到 printf() 调用。

注意:不想替换呼叫,只是重定向

所以我写了一些代码来做到这一点:

#ifndef EMBED
#define syslog(level, stuff) printf("SYSLOG: %s\n", stuff)
#endif

在我使用它的一个文件中效果很好。我把它移到了一个新文件并得到了一个错误:

error: macro "syslog" passed 3 arguments, but takes just 2

我知道错误是因为新文件中的调用是混合的,有些使用 2 个 syslog 参数,有些使用 3 个。我也知道我需要通过变量参数列表以某种方式重定向它,但我该怎么做呢?我还没有让它工作...

据我了解, syslog() 和 printf() 应该是:

void syslog(int priority, const char *format, ...)
int printf(const char *format, ...)

所以我尝试了:

#define ERR 3
#ifndef EMBED         // This is not defined in my env, btw
#define syslog(pri, fmt, ...) printf(fmt, ...)
#endif
...
void main() {
...
syslog(ERR, "test");

但这给出了错误:

error: expected expression before ‘...’ token

关于这个宏应该如何看待/使用的建议?

4

3 回答 3

11

GCC 在这方面有一个扩展,但最便携的处理方式是:

#define syslog(priority, ...)    printf(__VA_ARGS__)

优先级是强制性的,但被宏扩展忽略。其余参数(强制格式加上可选的后续参数)在__VA_ARGS__参数列表中使用printf()。无论格式字符串是常量(文字)还是变量,这都可以。


如果您想将输出标记为 的代理项syslog(),我会调用一个函数printf()来完成这项工作:

#define syslog(priority, ...) syslog_print(__VA_ARGS__)

甚至

#define syslog(priority, ...) syslog_print(__FILE__, __LINE__, __func__, __VA_ARGS__)

这些将被声明为:

extern void syslog_printf(const char *fmt, ...);

或者:

extern void syslog_printf(const char *file, int line, const char *func,
                          const char *fmt, ...);

该实现是宏的直接应用<stdarg.h>以及以下v*printf()功能:

void syslog_printf(const char *file, int line, const char *func,
                   const char *fmt, ...)
{
    va_list args;
    printf("SYSLOG:%s:%d:%s: ", file, line, func);
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

您可以添加时间戳和您喜欢的任何其他内容;您还可以轻松地将输出安排到文件而不是标准输出;您还可以安排它在功能内打开或关闭。因此,平均而言,我会替换syslog()为一个代理项,该代理项允许您调整代码对设施的使用。

事实上,既然您发现了更改日志记录行为的要求,我建议您不要直接在代码中使用,而应该在syslog()您的代码中使用自己的函数(例如,syslog_printf()代码,并为您提供该功能的各种实现。这样做的唯一缺点syslog()是现在更难调用真实数据 - 没有vsyslog()AFAIK。因此,基本调用syslog()将通过在syslog_printf()using中格式化字符串vsnprintf()(或者vasprintf()如果这对您可用并且内存耗尽不是一个可能的问题),然后syslog()使用预格式化的字符串 ( syslog(priority, "%s", buffer);) 调用来完成。当然,您还希望将优先级传递给 relay to 的代理函数syslog()

于 2012-08-27T15:06:10.023 回答
1

如果您不想依赖可变参数宏(C99 功能),您也可以这样做:

#define syslog my_syslog

static inline int my_syslog(int prio, const char *fmt, ...)
{
    int r;
    va_list ap;
    va_start(ap, fmt);
    r = vprintf(fmt, ap);
    va_end(ap);
    return r;
}

或类似的。

于 2012-08-27T15:57:54.943 回答
1

fmt字符串应包含其自己的格式说明符,这些说明符用可变参数填充。首先,您可以简单地忽略实际参数并打印格式化字符串。你需要一个可变参数宏:

#define syslog(level, fmt, ...) printf("SYSLOG: %s\n", fmt)

其次,如果您愿意冒巨大的风险并期望用户将格式化字符串作为文字而不是变量提供,您可以连接自己的字符串:

#define syslog(level, fmt, ...) printf("SYSLOG[%d] " fmt, level, ##__VA_ARGS__)

这适用于syslog(1, "Hello");,但不适用于syslog(1, str);

于 2012-08-27T14:59:09.880 回答