2010-03-01 3 views
22

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

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

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

У компилятора Microsoft C/C++ есть что-то похожее?

ответ

4

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

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

+1

На самом деле, похоже, что проверка завершена: см. [Ответ шестизначных переменных] (http://stackoverflow.com/questions/2354784/attribute-formatprintf-1-2-for-msvc/6849629#6849629). –

+0

@RaphaelISP: Если вы прочтете ссылку в этом ответе, вы увидите, что аннотации SAL игнорируются, если параметр [/analyze](http://msdn.microsoft.com/en-us/library/ms173498.aspx) , и это доступно только в корпоративных версиях Visual Studio. Кроме того, проверки, которые затем выполняются, не имеют того же типа, что и GCC. Альтернативный ответ через год после запроса вряд ли оправдал нисходящий ответ на принятый ответ, не понимая применимости альтернативы. – Clifford

+1

@Raphae:/анализ выполняет ряд проверок, связанных с строками типа printf (см. [C6270-C6274] (http://msdn.microsoft.com/en-us/library/a5b9aa09.aspx) и др.), Но они не так глубоки, как GCC. Единственное в-предприятии - это только проблема «сорта», так как вам следует избегать VS, если вы его не покупаете. – user7116

1

Там интересная статья на тему о проекте Код: «Использование C++ Шаблоны для запуска Validation» Александр Горобец http://www.codeproject.com/KB/cpp/ValidateprintfFunction.aspx

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

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 ...

15

Использование SAL Annotations вы можете использовать _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), ...); 
+3

Игнорируется за пределами выпусков «Предприятие» с параметром/анализом. – Clifford

+0

Я предлагаю избегать VS, если вы не покупаете корпоративную версию. – user7116

+3

Действительно? Зачем? Даже бесплатное Express Edition является полностью способным компилятором C/C++ с первоклассным отладчиком. Возможно, для этого потребуется «Enterprise» (в основном предприятия), но то, что предлагает «Enterprise», является дополнительным для основного компилятора и отладчика. – Clifford

2

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

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

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

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

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

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

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

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

Смежные вопросы