__attribute __ ((формат (printf, 1, 2))) для MSVC? - PullRequest
23 голосов
/ 01 марта 2010

С помощью GCC я могу указать __attribute__((format(printf, 1, 2))), сообщая компилятору, что эта функция принимает параметры vararg, которые являются спецификаторами формата printf.

Это очень полезно в случаях, когда я обертываю, например. семейство функций vsprintf. я могу иметь extern void log_error(const char *format, ...) __attribute__((format(printf, 1, 2)));

И всякий раз, когда я вызываю эту функцию, gcc проверяет, соответствуют ли типы и число аргументов заданным спецификаторам формата, как это было бы для printf, и выдает предупреждение, если нет.

Имеет ли компилятор Microsoft C / C ++ что-нибудь подобное?

Ответы [ 4 ]

16 голосов
/ 27 июля 2011

Используя Аннотации SAL , вы можете использовать _Printf_format_string_ (для VS2k8 или VS2k10) или __format_string (для VS2k5):

#undef FORMAT_STRING
#if _MSC_VER >= 1400
# include <sal.h>
# if _MSC_VER > 1400
#  define FORMAT_STRING(p) _Printf_format_string_ p
# else
#  define FORMAT_STRING(p) __format_string p
# endif /* FORMAT_STRING */
#else
# define FORMAT_STRING(p) p
#endif /* _MSC_VER */

/* use /analyze or _USE_ATTRIBUTES_FOR_SAL for checking */
extern void log_error(FORMAT_STRING(const char* format), ...);
5 голосов
/ 18 февраля 2017

Как упоминалось ранее @RustyX printf проверка формата теперь поддерживается по умолчанию с VC2015 . То есть без a /analyze прохода статического анализа. К сожалению, пока нет механизма для маркировки пользовательских функций-оболочек.

Это предполагает очевидный обходной путь вызова printf . Это определение макроса, который вызывает как пользовательскую функцию, так и сам printf. Последний на мертвом пути должен быть оптимизирован.

Это дает дополнительное преимущество в достижении некоторого уровня переносимости для других компиляторов.

int printf_wrapper_(const char *format, ...);

#define printf_wrapper(...) \
(printf || printf(__VA_ARGS__), printf_wrapper_(__VA_ARGS__))

Недостатком является то, что VC2015 выполняет некоторое элементарное удаление мертвого кода до проверки формата, проверяя только оставшийся живой код.

Таким образом sizeof или константные условные выражения потерпят неудачу. Как правило, если отладочная сборка выдает код времени выполнения, вы получите предупреждение, хотя более поздние передачи в сборках выпуска могут по-прежнему завершать вызов.

Увы, из-за этого движущаяся цель может измениться в будущих версиях компилятора. Хоть и относительно мягкий.

4 голосов
/ 01 марта 2010

Хотя GCC проверяет спецификаторы формата, когда -Wformat включен, VC ++ не имеет такой проверки, даже для стандартных функций, поэтому нет эквивалента этому __attribute__, потому что нет эквивалента -Wformat.

Я думаю, что акцент Microsoft на C ++ (о чем свидетельствует поддержание соответствия ISO для C ++ при поддержке только C89) может быть отчасти причиной того, что VC ++ не имеет проверки спецификаторов формата; в C ++ с использованием <iostream> указатели формата не нужны.

1 голос
/ 27 июля 2011

На тему Code Project есть интересная статья на эту тему: «Использование шаблонов C ++ для проверки запуска» Александр Горобец http://www.codeproject.com/KB/cpp/ValidateprintfFunction.aspx

Я изменил его так, что у меня есть макрос PRINTF_VALIDATE(format, ...), который регистрирует все ошибки формата при установке программы (фактически не нужно выполнять код). Он производит что-то вроде этого:

test.cpp(147) : error : 'printf' format character 'f' at position 1 does not match parameter type INT
test.cpp(147) : error : 'printf' too many arguments (3 instead of 2)

Можно использовать, например, так:

#define LOG(fmt, ...) do { PRINTF_VALIDATE(fmt, __VA_ARGS__); WriteLog(fmt, __VA_ARGS__); } while(0)

Это не так полезно, как поддержка компилятора, но работает в Visual Studio 2005 ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...