Модификатор __printflike__
Что такое "модификатор __printflike__"? Что означает этот термин?
3 ответа
В предположении он сообщает компилятору, что вы используете, что функция принимает аргументы в форме [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()
) и соответствующие ей аргументы (отформатированные с использованием строки формата) начинаются с пятого аргумента.
Это означает, что если я наберу:
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__ */
Вероятно, сообщает компилятору, что соответствующая функция имеет printf
семантика
Это может позволить компилятору выдавать предупреждения во время компиляции, когда модификаторы в строке формата не соответствуют типу или количеству переданных аргументов.
Нет другого способа, которым компилятор мог бы сказать, что %u
не правильное форматирование для int
при звонке printf
, sprintf
, fprintf
, так далее.
Несколько месяцев назад я задал обратный вопрос: являются ли предупреждения компилятора printf/sprintf концептуальным разрывом?