我的桌面上运行着一个linux应用程序,我想将syslog()调用重定向到printf()调用。
注意:我不想替换调用,只是重定向
所以我写了一些代码来做到这一点:
#ifndef EMBED
#define syslog(level, stuff) printf("SYSLOG: %sn", stuff)
#endif
在我使用它的一个文件中效果很好。我把它移到一个新文件中,得到了一个错误:
error: macro "syslog" passed 3 arguments, but takes just 2
我知道这个错误是因为新文件中的调用是混合的,有些对syslog使用了2个参数,有些使用了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
关于此宏的外观/使用方式的建议?
GCC在这一领域有一个扩展,但最便携的处理方式是:
#define syslog(priority, ...) printf(__VA_ARGS__)
优先级是强制性的,但被宏扩展忽略。其余参数(强制格式加上可选的后续参数)在printf()
的参数列表中使用的__VA_ARGS__
中。无论格式字符串是常量(文字)还是变量,都可以。
如果您想将输出标记为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()
的基本调用将通过使用vsnprintf()
格式化syslog_printf()
中的字符串(或者vasprintf()
,如果这对您来说是可用的,并且内存耗尽不是一个可能的问题),然后使用预格式化的字符串(syslog(priority, "%s", buffer);
)调用syslog()
来完成。当然,您还希望将优先级传递给代理函数,以便中继到syslog()
。
fmt
字符串应包含其自己的格式说明符,这些说明符由可变参数填充。首先,您可以简单地忽略实际参数,只打印格式化字符串。你需要一个可变宏:
#define syslog(level, fmt, ...) printf("SYSLOG: %sn", fmt)
其次,如果你愿意冒巨大的风险,并期望用户将格式化字符串作为文本而不是变量提供,你可以连接你自己的字符串:
#define syslog(level, fmt, ...) printf("SYSLOG[%d] " fmt, level, ##__VA_ARGS__)
这对syslog(1, "Hello");
有效,但对syslog(1, str);
无效。
如果你不想依赖可变宏(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;
}
或类似的。