这听起来有点像面试问题,但实际上是一个实际问题。
我正在使用嵌入式平台,并且仅提供这些功能的等价物:
此外,printf()实现(和签名)很可能在不久的将来发生变化,因此对它的调用必须驻留在一个单独的模块中,以便以后轻松迁移。
鉴于这些,我可以在某些函数或宏中包装日志记录吗?目标是我的源代码在一千个地方调用THAT_MACRO("Number of bunnies: %d", numBunnies);
,但只能在一个地方看到对上述函数的调用。
编译器:arm-gcc -std = c99
答案 0 :(得分:49)
有两种方法可以做到这一点:
Variadric宏
#define my_printf(...) printf(__VA_ARGS__)
转发va_args
#include <stdarg.h>
#include <stdio.h>
void my_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
还有vsnprintf
,vfprintf
以及stdio
中您能想到的任何内容。
答案 1 :(得分:32)
由于你可以使用C99,我将它包装在variadic macro:
中#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)
因为你没有说你有vprintf
或类似的东西。如果你确实有这样的东西,你可以将它包装在谢尔盖L在他的答案中提供的功能中。
上述TM_PRINTF不适用于空的VA_ARGS列表。 至少在GCC中可以写:
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
如果__VA_ARGS__
为空,则两个##符号删除删除前面多余的逗号。
答案 2 :(得分:10)
如果您不得不将呼叫包裹在两个括号中,您可以这样做:
#define THAT_MACRO(pargs) printf pargs
然后使用它:
THAT_MACRO(("This is a string: %s\n", "foo"));
^
|
OMG
这是有效的,因为从预处理器的角度来看,整个参数列表变成一个宏参数,用括号替换。
这比仅仅做得好
更好#define THAT_MACRO printf
因为它允许你定义它:
#define THAT_MACRO(pargs) /* nothing */
这将“吞噬”宏参数,它们永远不会成为编译代码的一部分。
UPDATE 当然在C99中,这种技术已经过时,只需使用可变参数宏并感到高兴。
答案 3 :(得分:9)
#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
##
令牌将启用TM_PRINTF("aaa");
答案 4 :(得分:3)
#define PRINTF(...) printf(__VA_ARGS__)
这样的工作原理如下:
它定义参数化宏PRINTF接受(最多)无限参数,然后将其从PRINTF(...)
预处理到printf(__VA_ARGS__)
。参数化宏定义中使用__VA_ARGS__
来表示给定的参数('因为你不能命名无限参数,是吗?)。
答案 5 :(得分:2)
有限的图书馆?嵌入式系统?需要尽可能多的性能?没问题!
正如对this question的回答所示,您可以使用汇编语言将不接受VA_LIST的函数包装成那些以低成本实现您自己的vprintf的函数!
虽然这会起作用,并且几乎肯定会产生你想要的性能和抽象,但我建议你可以通过切片uClibc的部分来获得一个功能更丰富的标准库。除非您绝对需要每个周期,否则这样的解决方案肯定是比使用装配更便携和整体更有用的答案。
毕竟这就是为什么存在这样的项目。
答案 6 :(得分:0)
这是@ ldav1出色答案的稍作修改的版本,它在日志之前显示时间:
#define TM_PRINTF(f_, ...) \
{ \
struct tm _tm123_; \
struct timeval _xxtv123_; \
gettimeofday(&_xxtv123_, NULL); \
localtime_r(&_xxtv123_.tv_sec, &_tm123_); \
printf("%2d:%2d:%2d.%d\t", _tm123_.tm_hour, _tm123_.tm_min, _tm123_.tm_sec, _xxtv123_.tv_usec); \
printf((f_), ##__VA_ARGS__); \
};