__attribute __((格式(printf,1,2)))对于MSVC?

使用GCC,我可以指定__attribute__((format(printf, 1, 2))) ,告诉编译器该函数采用printf格式说明符的vararg参数。

这在我包装例如vsprintf函数系列的情况下非常有用。 我可以有extern void log_error(const char *format, ...) __attribute__((format(printf, 1, 2)));

每当我调用这个函数时,gcc将检查参数的类型和数量是否与printf一样符合给定的格式说明符,如果没有则发出警告。

Microsoft C / C ++编译器是否有类似的东西?

虽然GCC在启用-Wformat时检查格式说明符,但VC ++没有这样的检查,即使对于标准函数也是如此,因此没有等效的__attribute__因为没有等效的-Wformat。

我认为微软强调C ++(通过维持C ++的ISO兼容性而仅支持C89)可能部分是VC ++没有格式说明符检查的原因; 在C ++中使用格式说明符是不必要的。

使用SAL Annotations,您可以使用_Printf_format_string_ (从VS2k8或VS2k10开始)或__format_string (对于VS2k5):

 #undef FORMAT_STRING #if _MSC_VER >= 1400 # include  # 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), ...); 

正如之前提到的@RustyX ,从VC2015开始 ,默认支持printf格式检查。 那是没有 /analyze静态分析通过。 遗憾的是,还没有一种标记用户定义的包装函数的机制。

这表明调用printf的明显解决方法。 这是定义一个宏,它调用用户定义的函数以及printf本身。 后者在一条死路上进行优化。

这具有为其他编译器实现某种程度的可移植性的额外好处。

 int printf_wrapper_(const char *format, ...); #define printf_wrapper(...) \ (printf || printf(__VA_ARGS__), printf_wrapper_(__VA_ARGS__)) 

缺点是VC2015在格式检查之前执行一些基本的死代码消除,仅测试剩余的实时代码。

因此sizeof或constant条件表达式将失败。 根据经验,如果调试版本发出运行时代码,那么您将收到警告,但稍后在版本构建中传递可能仍然会终止该调用。

这使得它在未来的编译器版本中易于改变。 虽然相对温和。

关于代码项目的主题有一篇有趣的文章:“使用C ++模板进行启动validation”作者:Alexander Gorobets 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 …