MSVC相当于__attribute __((warn_unused_result))?

我发现__attribute__ ((warn_unused_result))作为一种鼓励开发人员不要忽略函数返回的错误代码的方法非常有用,但我需要使用它来处理MSVC以及gcc和gcc兼容的编译器,如ICC。 Microsoft Visual Studio C / C ++编译器是否具有等效机制? (到目前为止,我试过通过MSDN没有任何运气。)

这是_Check_return_ 。 请参阅此处获取类似注释的示例, 此处为function行为。 它自MSVC 2012以来得到支持。

例:

 _Check_return_ int my_return_must_be_checked() { return 42; } 

2012年MSVC及更新版本的更新

非常感谢@Albert指出,当使用SAL静态代码分析时,MSVC现在支持Visual Studio 2012中的注释_Check_return_ 我正在添加这个答案,以便我可以包含一个可能对其他人有用的跨平台宏:

 #if defined(__GNUC__) && (__GNUC__ >= 4) #define CHECK_RESULT __attribute__ ((warn_unused_result)) #elif defined(_MSC_VER) && (_MSC_VER >= 1700) #define CHECK_RESULT _Check_return_ #else #define CHECK_RESULT #endif 

请注意,与gcc 等人不同,(a)MSVC要求对函数的声明定义进行注释,并且(b)注释需要在声明/定义的开头(gcc允许)。 因此通常需要使用例如:

 // foo.h CHECK_RETURN int my_function(void); // declaration 

 // foo.c CHECK_RETURN int my_function(void) // definition { return 42; } 

另请注意,如果从命令行进行编译,则需要/analyze (或-analyze )开关,如果使用Visual Studio IDE,则需要等效。 这也有助于减缓构建速度。

一些版本的VisualStudio包含一个静态分析工具,以前称为PREFast (现在简称为“C / C ++代码分析”)。 PREFast使用注释来标记代码。 其中一个注释, MustCheck , 可以满足您的需求。

据我所知,MS编译器没有等效的pragma或属性 – 当您使用适当的警告级别打开优化器时,可以获得的唯一“未使用”类型警告是变量。

我认为其他人提到的SAL注释是MSVC的正确答案,但我猜有些人会对MSVC,GCC和GCC兼容编译器的可移植性感兴趣,所以……

首先,GCC仅支持自3.4以来的warn_unused_result 。 您可能想要检查__GNUC__ / __GNUC_MINOR__的值,而不仅仅是检查是否定义了__GNUC__ ,尽管此时我无法想象任何人使用的是早于3.4的GCC版本。

有几个编译器支持GCC风格的函数属性,可能会也可能不会定义__GNUC__和朋友:

  • Clang(检查__has_attribute(warn_unused_result) )和基于它的编译器(emscripten,xlc 13+,armclang等),虽然AFAIK它总是伪装成至少GCC 4.2,所以你可能不需要显式检查。
  • 英特尔并不总是定义__GNUC__ -no-gcc (请参阅-no-gcc标志)。 我不知道他们何时开始支持它(他们的文档严重缺乏),但我知道16.0+是安全的。
  • TI 8.0+支持它
  • 当–gcc通过时,TI 7.3+支持它; __TI_GNU_ATTRIBUTE_SUPPORT__将被定义。
  • Oracle Developer Studio 12.6+在C ++模式下支持它, 但不支持C.
  • PGI在C ++模式下支持它。 AFAICT它没有记录,所以我不确定它何时被添加(它是#1650-D),但它绝对存在于17.10+中。 它在C模式下被默默忽略,希望它们有一天会实现它。

另外,C ++ 17添加了[[nodiscard]]属性。 对于在C ++ 17模式下支持[[nodiscard]]的GCC / clang版本,您也可以在C ++ 11及更高版本模式下使用[[gnu::nodiscard]] ,但如果您将其隐藏在宏后面无论如何我没有看到这样做的理由而不是仅使用__attribute__((__warn_unused_result__))

把它放在一起,在Hedley中有一个HEDLEY_WARN_UNUSED_RESULT宏,看起来像:

 #if defined(__cplusplus) && (__cplusplus >= 201703L) # define HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] #elif \ HEDLEY_GNUC_HAS_ATTRIBUTE(warn_unused_result,3,4,0) || \ HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \ HEDLEY_TI_VERSION_CHECK(8,0,0) || \ (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ (HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ HEDLEY_PGI_VERSION_CHECK(17,10,0) # define HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) #elif defined(_Check_return_) /* SAL */ # define HEDLEY_WARN_UNUSED_RESULT _Check_return_ #else # define HEDLEY_WARN_UNUSED_RESULT #endif 

如果您不想使用Hedley(它的公共域/ CC0),您应该能够删除内部Hedley宏并且只需复制逻辑而不会有太多麻烦。 如果您选择这样做,您可能应该将您的端口设置为回购中的版本,因为我不太可能记得使用新信息保持此答案的最新状态。