[ACCEPTED]-__attribute__((format(printf, 1, 2))) for MSVC?-visual-c++

Accepted answer
Score: 20

Using SAL Annotations you can use _Printf_format_string_ (as of VS2k8 or VS2k10) or 1 __format_string (for VS2k5):

#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 */
# 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), ...);
Score: 9

As previously mentioned by @RustyX printf format 21 checking is now supported by default as of VC2015. That 20 is without a /analyze static analysis pass. Regrettably 19 there is not yet a mechanism for marking 18 user-defined wrapper functions.

This suggest 17 the obvious workaround of calling printf. That is defining 16 a macro which invokes both the user-defined 15 function as well as the printf itself. The latter 14 on a dead path to be optimized out.

This 13 has the added benefit of achieving some 12 level of portability to other compilers.

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

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

The 11 drawback is that VC2015 performs some rudimentary 10 dead-code elimination prior to the format 9 check, testing only the remaining live code.

Thus 8 sizeof or constant conditional expressions will 7 fail. As a rule of thumb if a debug build 6 emits run-time code then you will get the 5 warning, though later passes in release 4 builds may still kill the call.

Alas this 3 makes it something of a moving target liable 2 to change in future compiler versions. Albeit 1 a relatively benign one.

Score: 7

While GCC checks format specifiers when 9 -Wformat is enabled, VC++ has no such checking, even 8 for standard functions so there is no equivalent 7 to this __attribute__ because there is no equivalent 6 to -Wformat.

I think Microsoft's emphasis 5 on C++ (evidenced by maintaining ISO compliance 4 for C++ while only supporting C89) may be 3 in part the reason why VC++ does not have 2 format specifier checking; in C++ using 1 <iostream> format specifiers are unnecessary.

Score: 3

There is an interesting article on the subject 9 on Code Project: "Using C++ Templates 8 for Startup Validation" by Alexander 7 Gorobets http://www.codeproject.com/KB/cpp/ValidateprintfFunction.aspx

I've modified it so that I have 6 a macro PRINTF_VALIDATE(format, ...) that logs all format errors at program statup (there's 5 no need to actually execute the code). It 4 produces something like this:

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)

One can use 3 it for example like this:

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

This is not as 2 useful as compiler support, but it works 1 on Visual Studio 2005...

Score: 0

Workaround for MSVS, GCC and clang: "If 9 you’re using a macro to call your printf-like 8 functions, you can use a helper-macro to 7 get compile time format checks like this:

#define CHECK_FORMAT(...)                               \
    do {                                                \
        char const dummy = sizeof(printf(__VA_ARGS__)); \
        (void)dummy;                                    \
    } while (false)

#define MY_FMT(...)                                    \
    do {                                               \
        CHECK_FORMAT(__VA_ARGS__);                     \
        MyFormatFunc(__FILE__, __LINE__, __VA_ARGS__); \
    } while (false)


The 6 printf call in the sizeof isn’t evaluated 5 so it doesn’t generate code, but current 4 versions of MSVC, GCC and Clang will still 3 do the format-string check so you get the 2 warning. The local dummy variable is also 1 optimized away with -O2."


More Related questions