27

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

4

5 回答 5

16

_Check_return_。有关类似注释的示例,请参见此处,有关功能行为,请参见此处。从 MSVC 2012 开始支持它。

例子:

_Check_return_
int my_return_must_be_checked() {
    return 42;
}
于 2014-03-31T07:12:23.437 回答
14

MSVC 2012 及更高版本的更新

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

#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(或)开关,如果使用 Visual Studio IDE,则需要等效开关。-analyze这也往往会稍微减慢构建速度。

于 2014-03-31T10:33:45.203 回答
5

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

于 2010-11-19T15:34:32.400 回答
3

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

于 2010-11-19T15:21:02.943 回答
2

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

首先,GCC 仅支持warn_unused_result自 3.4 以来。您可能 想要检查__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标志)。我不知道他们什么时候开始支持它(他们的文档严重缺乏),但我知道 16.0+ 是安全的。
  • TI 8.0+ 支持
  • TI 7.3+ 支持通过 --gcc ; __TI_GNU_ATTRIBUTE_SUPPORT__将被定义。
  • Oracle Developer Studio 12.6+ 在 C++ 模式下支持它,但不支持 C
  • PGI 在 C++ 模式下支持它。AFAICT 它没有记录,所以我不确定它是什么时候添加的(它是#1650-D),但它肯定存在于 17.10+ 中。它在 C 模式下被默默地忽略,希望他们有一天会实现它。

此外,C++17 添加了一个[[nodiscard]]属性。对于支持[[nodiscard]]C++17 模式的 GCC/clang 版本,您也可以 [[gnu::nodiscard]]在 C++11 和更高模式下使用,但是如果您将它隐藏在宏后面,我看不出有这样做的理由,而不是只是使用__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 宏并复制逻辑而不会太麻烦。如果您选择这样做,您可能应该将您的端口基于 repo 中的版本,因为我不太可能记得使用新信息保持这个答案是最新的。

于 2018-03-24T18:33:45.753 回答