我创建了一个宏,它将打印所有打印的时间戳。
void timestamp()
{
struct timeval tv;
gettimeofday(&tv,NULL);
printf("%d",tv.tv_sec );
}
#define printf_all(format, ...) { \
static const char format_string[] = format; \
printf(format_string, ##__VA_ARGS__); \
timestamp(); \
}
int main()
{
printf_all("%d\n",10);
return 0;
}
我想将此宏转换为函数。但是在传递论据时我遇到了问题。
void printf_timestamp(static const char format_string[]) {
static const char format_string[] = format;
printf(format_string, ##__VA_ARGS__);
timestamp();
}
答案 0 :(得分:5)
您可以使用vprintf
:
int printf_timestamp(const char* fmt, ...) {
va_list args;
int result;
va_start(args, fmt);
result = vprintf(fmt, args);
va_end(args);
timestamp();
return result;
}
答案 1 :(得分:0)
这通常使用vprintf()
函数来完成,正如orlp所解释的那样。但是,单独使用一种格式无法进行类型检查:通常,您的编译器会在它看到的每个printf()
调用中解释格式字符串文字,以确定相应的参数是否具有正确的类型。
有些编译器允许您添加对此类型检查的支持,以下是__attribute__(())
所需的gcc
:
//within header
void printfTimestamp(const char* format, ...)
__attribute__((format(printf, 1, 2)));
//within implementation file
void printfTimestamp(const char* format, ...) {
va_list args;
va_start(args, format);
int result = vfprintf(stderr, format, args);
va_end(args);
timestamp();
return result;
}
属性的参数是带有格式字符串(1
)的参数号和第一个变量参数位置(2
)。因此,如果要向函数添加其他参数,则应将其声明为:
void myPimpedPrintf(int foo, const char* format, ...)
__attribute__((format(printf, 2, 3)));
答案 2 :(得分:0)
如果只是添加一个时间戳,我同意orlp提出的vprintf()
是要走的路。但是,我认为有一个有利于宏的有效论据,那就是使用其他编译器内置宏,如__LINE__
,__FILE__
和__func__
,我个人非常喜欢对记录有用。
我通常会使用gcc
以及其他任何可以吞咽逗号的内容。
#define log_debug(M, ...) do{ \
struct timespec _ts; \
double _ts_sec; \
clock_gettime(CLOCK_MONOTONIC, &_ts);\
_ts_sec = _ts.tv_nsec * 1e-9 + _ts.tv_sec; \
fprintf(stderr, "%.3f [DEBUG] (%s:%d) " M, _ts_sec, \
__func__, __LINE__, ##__VA_ARGS__); \
}while(0)
// usage:
log_debug("x=%d\n", x);
这里有一些你可能不熟悉的“技巧”。
第一个是do{}while()
循环。这是用于编写多语句宏的相当常见且基本上可移植的C语言。它允许您使用宏在;
中终止它,并允许声明范围变量。然而,是一个陈述,而不是一个表达,所以没有“返回值”。通常对于像macros这样的printf()并不重要,但要注意,在尝试制作类似函数的宏时,这可能会让你感到厌烦。
另一个“技巧”是使用逗号吞噬'##'运算符。在此处阅读更多内容:https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
此外,这利用了背靠背字符串文字在C中连接形成单个字符串文字的事实。缺点是这种技术仅适用于字符串文字,即您的格式字符串不能在变量中。