究竟什么是“__printflike__ 修饰符”?这个词是什么意思?
3 回答
猜测一下,它会告诉您正在使用的编译器,一个函数接受参数的形式[anything, ] format, ...
,其format, ...
部分看起来像printf
. 该__printflike__
属性允许编译器根据字符串格式测试参数列表中的类型。当您在将字符串发送到某些特殊的日志接口之前编写一个类似log(format, ...)
并使用vsprintf
将格式化工作从属于通常的标准库函数的函数时,就会出现这种情况。
如果您使用的是 GCC,那么它可能#define
在您的项目中类似于:
#define __printflike__ __attribute__((format(printf, 1, 2)))
Where1, 2
表示出format, ...
现在位置 1 和 2 中。
我的错误报告库中有一个函数,其标题中的声明如下:
extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...)
PRINTFLIKE(4,5);
PRINTFLIKE 是大写的,因此当我不使用 GCC 时,我可以将其定义为空。这个用法表示前三个参数没有什么特别的,但第四个参数是一个格式字符串,就像printf()
(实际上,在内部,它被传递给vfprintf()
)所使用的那样,并且与它对应的参数(使用格式字符串格式化)开始与第五个论点。
这意味着如果我输入:
err_logmsg(stdout, ERR_ABORT, 1, "%s: %d\n", errno, strerror(errno));
我会得到一个编译错误,因为errno
is anint
并strerror(errno)
返回一个指向字符串的指针。我可以通过更改格式字符串或第五个和第六个参数来修复错误。(ERR_ABORT 是在声明的同一标头中定义的一组标志err_logmsg()
。)
PRINTFLIKE 宏中有两个数字,因为格式字符串和格式字符串使用的第一个参数之间可能存在其他参数。例如,替代功能可以是:
extern void err_writer(FILE *fp, const char *format, int flags, int estat, ...)
PRINTFLIKE(2,5);
这告诉编译器格式字符串是第二个参数,但是被格式化的相应参数仍然从第五个参数开始出现。
此代码的头文件包含以下行:
#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN() __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN() /* If only */
#endif /* __GNUC__ */
可能告诉编译器相应的函数具有printf
类似的语义。
当格式字符串中的修饰符与传递参数的类型或计数不对应时,这可以使编译器在编译时发出警告。
编译器没有其他方法可以知道在调用时告诉您这%u
不是正确的格式, ,等。int
printf
sprintf
fprintf
几个月前我问了相反的问题:printf/sprintf 编译器警告是概念上的中断吗?