В моей библиотеке отчетов об ошибках есть функция с объявлением в заголовке:
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
является int
, а 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__ */