__printflike__修饰符
究竟什么是“__printflike__修饰符”? 这个术语是什么意思?
猜测它告诉编译器你正在使用一个函数接受[anything, ] format, ...
的forms的参数[anything, ] format, ...
format, ...
部分看起来像printf
的参数。 __printflike__
属性允许编译器根据字符串格式测试参数列表中的类型。 当你编写像log(format, ...)
这样的函数并使用vsprintf
将格式化工作从属于通常的标准库函数,然后将字符串发送到某个特殊的日志界面时,就会出现这种情况。
如果您正在使用GCC,那么它可能是您项目中的#define
,如:
#define __printflike__ __attribute__((format(printf, 1, 2)))
其中1, 2
表示format, ...
出现在第1和第2位。
我的错误报告库中有一个函数,标题中的声明如下:
extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5);
PRINTFLIKE是大写的,所以当我不使用GCC时,我可以将其定义为空。 这个用法说前三个参数没什么特别的,但是第四个参数是一个格式字符串,就像printf()
使用的那样(实际上,内部传递给vfprintf()
),以及vfprintf()
对应的参数(格式化)使用格式字符串)以第五个参数开头。
这意味着如果我输入:
err_logmsg(stdout, ERR_ABORT, 1, "%s: %d\n", errno, strerror(errno));
我将得到一个编译错误,因为errno
是一个int
和strerror(errno)
返回一个指向字符串的指针。 我可以通过更改格式字符串或第五和第六个参数来修复错误。 (ERR_ABORT是在同一标头中定义的一组标志,用于声明err_logmsg()
。)
PRINTFLIKE宏中有两个数字,因为格式字符串与格式字符串使用的第一个参数之间可能存在其他参数。 例如,替代function可以是:
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
的语义。
这可以使编译器在编译时发出警告,当格式字符串中的修饰符与传递的参数的类型或计数不对应时。
没有其他方法可以让编译器知道在调用printf
, sprintf
, fprintf
等时, %u
不是int
的正确格式。
几个月前我问过相反的问题: printf / sprintf编译器警告是否有概念上的突破?