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

时间:2010-03-01 09:21:27

标签: c++ c visual-c++

使用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 ++编译器有类似的东西吗?

4 个答案:

答案 0 :(得分:16)

使用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), ...);

答案 1 :(得分:5)

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

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

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

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

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

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

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

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

答案 2 :(得分:4)

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

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

答案 3 :(得分:1)

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