有时我会出于各种原因编写printf样式函数的包装器,我真的很喜欢让clang告诉我格式说明符和实际参数之间的类型不匹配。考虑:
#include <stdarg.h>
#include <stdio.h>
static __attribute__((format(printf, 1, 2))) void log(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
}
int main(void)
{
log("%s", 42);
return 0;
}
如果使用-Wall
编译,它会巧妙地告诉我类型错误:
test.c:14:15: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
log("%s", 42);
~~ ^~
%d
这对函数非常有效,但是当涉及函数指针时,__attribute__((format(printf, 1, 2)))
似乎不再有效。以下代码:
#include <stdarg.h>
#include <stdio.h>
typedef void (*log_t)(const char*, ...) __attribute__((format(printf, 1, 2)));
static __attribute__((format(printf, 1, 2))) void log(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
}
int main(void)
{
log_t func = &log;
(*func)("%s", 42);
return 0;
}
在-Wall
下编译时没有警告,但产生的程序会出现段错误。我尝试将属性说明符放在typedef的每个部分中,但它似乎没有什么区别。
有没有办法让clang为函数指针指定属性(或 this 属性),以便在编译时实际拾取它?
如果重要,我的clang将其版本报告为:Apple LLVM version 9.0.0 (clang-900.0.39.2)
。
答案 0 :(得分:2)
将属性说明符放在带有指针声明的行上(即产生关于不匹配参数的警告)
log_t func __attribute__((format(printf, 1, 2))) = log;
所以我认为如果目标是尽量减少输入并保持代码清洁,那么你仍然坚持使用宏。像这样:
#define checkargs __attribute__((format(printf, 1, 2)))
typedef void (*log_t)(const char*, ...);
static checkargs void log(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
vprintf(fmt, va);
va_end(va);
}
int main(void)
{
log_t checkargs func = log;
func("%s", 42);
}