我发现__attribute__ ((warn_unused_result))
这是一种非常有用的方法,可以鼓励开发人员不要忽略函数返回的错误代码,但我需要它与 MSVC 以及 gcc 和 gcc 兼容的编译器(如 ICC)一起使用。Microsoft Visual Studio C/C++ 编译器是否具有等效机制?(到目前为止,我已经尝试过 MSDN,但没有任何运气。)
5 回答
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
这也往往会稍微减慢构建速度。
VisualStudio 的某些版本附带一个静态分析工具,该工具以前称为PREFast(现在简称为“C/C++ 代码分析”)。PREFast 使用注释来标记代码。其中一个注释MustCheck 可以满足您的需求。
据我所知,MS 编译器没有等效的编译指示或属性 - 当您以适当的警告级别打开优化器时,您可以获得的唯一“未使用”类型警告是针对变量的。
我认为其他人提到的 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 中的版本,因为我不太可能记得使用新信息保持这个答案是最新的。