MSVC中与__attribute__ ((warn_unused_result))等效的是什么?

28
我发现 __attribute__ ((warn_unused_result)) 可以很好地鼓励开发人员不要忽略函数返回的错误码,但我需要它能够在 MSVC 和 gcc 以及兼容 gcc 的编译器上工作。微软 Visual Studio C/C++ 编译器是否有一个相同的机制?(我已经尝试阅读 MSDN,但迄今为止没有任何进展。)

2
当然可以,它被称为异常。 - Puppy
8
@DeadMG:是的,不幸的是这不像编译器警告那样立即出现,通常需要其他人来修复问题。 - Paul R
5个回答

18

这是_Check_return_。请参见此处以获取类似注释的示例,以及此处以获取函数行为。自MSVC 2012起支持该项。

示例:

_Check_return_
int my_return_must_be_checked() {
    return 42;
}

非常感谢 - 最初的问题是在2010年提出的,当时在MSVC中显然不存在这个功能,但现在已经被添加了,这是一个好消息。我想可以实现一个宏,首先检查 _MSCVER,然后如果支持就使用 _Check_return_ - Paul R
我现在已经将这个答案设为被接受的答案,因为它比之前的答案更加更新。我还添加了自己的答案,其中包括一个跨平台的宏,并检查了 MSVC 版本等。再次感谢! - Paul R
1
还有_Must_inspect_result_ - diapir
请注意,这个问题通常在编译过程中不会被捕捉到。您需要执行SAL静态代码分析才能收到此警告。 - undefined

13

MSVC 2012及更高版本更新

感谢@Albert指出,自Visual Studio 2012起,使用SAL静态代码分析时,MSVC现在支持注释_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时使用相应的开关。这也会导致构建速度有所降低。


5

VisualStudio的某些版本附带了一个静态分析工具,曾经被称为PREFast(现在简称为"C / C ++代码分析")。PREFast使用注释来标记代码。其中之一的注释MustCheck就是你要找的。


看起来很有趣 - 你能修复 MustCheck 的链接吗? - Paul R
@John + @Paul:http://www.microsoft.com/whdc/devtools/tools/annotations.mspx <-- 文档中的第一个示例包含__checkReturn注释 ;) - Billy ONeal
1
@Paul R - 请注意,这将大大减慢您的构建速度,并且还会生成许多您可能不关心的警告。我建议定期执行此操作,而不是在每次构建时执行,以避免对有价值的工具产生负面影响。 - Steve Townsend
1
目前Code Analysis实现中,这被称为Check_return - bfulgham
@bfulgham:谢谢你提供的信息。我现在大多数时间都不用VS堆栈了。你能否编辑我的答案并提供任何新信息?或者甚至提供你自己的答案。 - John Dibling
显示剩余3条评论

3
据我所知,微软编译器没有相应的#pragma或属性来警告“未使用”的类型 - 当您打开适当的警告级别并启用优化器时,您只能获得有关变量的“未使用”类型警告。

1
谢谢 - 有点讽刺的是,最需要这个功能的平台却不支持它的编译器。 - Paul R

2
我认为其他人提到的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等),虽然我知道它总是伪装成至少GCC 4.2,所以你可能不需要明确检查。
  • 英特尔并不总是定义__GNUC__(请参见-no-gcc标志)。我不知道他们何时开始支持它(他们的文档严重缺乏),但我知道16.0+是安全的。
  • TI 8.0+支持它
  • 当传递--gcc时,TI 7.3+支持它;当它被定义时,__TI_GNU_ATTRIBUTE_SUPPORT__将被定义。
  • Oracle Developer Studio 12.6+在C++模式下支持它,但不支持C
  • PGI在C++模式下支持它。据我所知,它没有记录,所以我不确定它是何时添加的(它是#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 宏,只需复制逻辑即可,如果你不想使用 Hedley(它是公共领域/CC0)。如果你选择这样做,你应该基于仓库中的版本进行移植,因为我很少会记得更新这个答案的新信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接