禁用单个警告错误

156

有没有一种方法可以在Visual Studio中禁用cpp文件中的单个警告行?

例如,如果我捕获了一个异常但没有处理它,那么我会得到错误4101(未引用的局部变量)。是否有一种方法可以仅在该函数中忽略此警告行,但在编译单元中报告其他警告行?目前,我将#pragma warning (disable : 4101)放在文件顶部,但这显然只会关闭整个编译单元的警告。


22
如果你只提到类型,而不给出异常名称,就不会有警告。例如:catch (const std::exception& /* unnamed */) {.... }。这并没有回答你的问题,但可能解决了你的问题。 - Sjoerd
1
谷歌搜索“如何在C++中抑制-Wunused-result”将带您到这里,因此这里提供了针对这种特定情况的答案:https://dev59.com/4Ww05IYBdhLWcg3wkirX#63512122。 - Gabriel Staples
11个回答

215
#pragma warning( push )
#pragma warning( disable : 4101)
// Your function
#pragma warning( pop ) 

1
@Cookie:是的,它适用于通过编译器的任何代码片段。 - Matteo Italia
对于更近期、更简明的答案,请查看下面的Daniel Seither的回答。 - Dan Nissenbaum
4
“clang”似乎不支持这个编译指示,但是您可以通过使用#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wunused-variable"#pragma clang diagnostic pop来实现相同的效果。请参见Clang用户手册中的“通过Pragmas控制诊断”一节。 - rampion
由于我很少使用这个功能,所以每次使用时,我通常会来到这个页面来提醒自己语法。我只是将它放在一个可能永远不会更新的弃用函数的调用周围,这样警告就不会在编译器列表中打扰我,而我会虔诚地扫描它们。 - David A. Gray
对于Visual Studio,命令行参数是/wd4101。请注意,标志和数字之间没有正常的:,并且您不能使用逗号分隔的数字列表。对于其他编译器,可能会改为/nowarn:4101 - Jesse Chisholm
有没有一种与编译器无关的方法来做到这一点?(gcc、VS、clang等)? - wcochran

134

如果您只想在单行代码(预处理后)中抑制警告[1],则可以使用suppress warning specifier

#pragma warning(suppress: 4101)
// here goes your single line of code where the warning occurs

对于一行代码而言,这与编写以下内容的效果相同:

#pragma warning(push)
#pragma warning(disable: 4101)
// here goes your code where the warning occurs
#pragma warning(pop)

[1] 在下面的评论中,其他人已经注意到如果以下语句是一个#include语句,那么#pragma warning(suppress: 4101)语句将不能有效地抑制头文件中每一行的警告。如果有意这样做,就需要使用push/disable/pop方法。


10
非常有用!不幸的是,对于包含生成警告的标题的单行无效。 - Marko Popovic
4
suppress修饰符作用于一行预处理代码。如果#pragma warning(suppress: ...)之后的行是一个#include指令(将其参数所引用的文件扩展到当前编译单元),则该效果仅适用于该文件的第一行。这显而易见,因为编译器生成警告。编译器对预处理代码进行操作。 - IInspectable
在这种情况下,我会称其为后处理的代码行。预处理意味着它尚未被预处理器翻译。 - void.pointer
2
@voi:*"-ed"* 结尾表示 过去分词。它用于表达某事已经在过去结束了。一个 "pre-processed" 的行是一个已经完全处理过的行。 - IInspectable
这些注释让我有点困惑,如果有人和我一样不理解,它们的意思是 #pragma warning(suppress: 4101) \n #include "wholeFile.h 不会抑制整个头文件中的错误(显然,但注释通常指向不明显的行为,因此会引起困惑)。你可以在头文件本身中使用它,没问题。 - Anne Quinn

30

#pragma push/pop通常用于解决这种问题,但在这种情况下为什么不直接删除未被引用的变量呢?

try
{
    // ...
}
catch(const your_exception_type &) // type specified but no variable declared
{
    // ...
}

6
这不是对问题的回答。尽管这可能解决了原帖作者的问题,但它并不能帮助未来读者解决类似问题:“如何关闭代码中特定部分的特定警告?” - Sjoerd
1
@Sjoerd:已经有三个人回答了其他人可能会搜索的“官方问题”,所以我尝试在行间读出他的实际问题并解决它(比你的评论晚了一分钟:P)。 - Matteo Italia
15
作为未来的读者,我可以证实这个答案确实对我有帮助。 - Mołot
2
@Mołot:作为一位过去的作者,我很高兴它能帮到你。=) - Matteo Italia
十年过去了,我仍然不使用异常处理...很多时候我会使用(cl.exe)的/kernel开关进行编译。 - Chef Gladiator

11

例子:

#pragma warning(suppress:0000)  // (suppress one error in the next line)

这个编译指示在 Visual Studio 2005 开始适用于C++
https://msdn.microsoft.com/en-us/library/2c8f766e(v=vs.80).aspx

这个编译指示在 Visual Studio 2005 到 Visual Studio 2015 中不适用于C#,会出现错误:“Expected disable or restore”。
(我猜他们从来没有实现过suppress...)
https://msdn.microsoft.com/en-us/library/441722ys(v=vs.140).aspx

C#需要一种不同的格式。它看起来像这样(但是无法工作):

#pragma warning suppress 0642  // (suppress one error in the next line)

不要使用 suppress,而是要使用 disableenable

if (condition)
#pragma warning disable 0642
    ;  // Empty statement HERE provokes Warning: "Possible mistaken empty statement" (CS0642)
#pragma warning restore 0642
else

太丑了,我觉得重新设计它更加聪明:

if (condition)
{
    // Do nothing (because blah blah blah).
}
else

9
如 @rampion 所述,如果您在使用 clang gcc,警告是按名称而不是数字进行分类的,您需要执行以下操作:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"
// ..your code..
#pragma clang diagnostic pop

这些信息来自这里


9

使用 #pragma warning ( push ),然后使用 #pragma warning ( disable ),再编写你的代码,最后使用 #pragma warning ( pop )。详细说明可参见这里

#pragma warning( push )
#pragma warning( disable : WarningCode)
// code with warning
#pragma warning( pop ) 

1
你怎样获取警告代码?我遇到了这个警告:expression must have a constant value C/C++(28)。但是把警告代码写作28并没有起作用! - Sourav Kannantha B

6

也可以使用在 WinNT.H 中定义的 UNREFERENCED_PARAMETER。其定义如下:

#define UNREFERENCED_PARAMETER(P)          (P)

并且像这样使用:

void OnMessage(WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(wParam);
    UNREFERENCED_PARAMETER(lParam);
}

你可能会争辩为什么要使用它,因为你可以省略变量名本身。然而,在某些情况下(不同项目配置,Debug/Release构建),该变量可能实际被使用。在另一个配置中,该变量未使用(因此会产生警告)。

一些静态代码分析仍可能对这个无意义的语句(wParam;)发出警告。在这种情况下,你可以使用 DBG_UNREFERENCED_PARAMETER,在调试构建中与 UNREFERENCED_PARAMETER 相同,在发布构建中执行 P=P

#define DBG_UNREFERENCED_PARAMETER(P)      (P) = (P)

1
请注意,自C++11以来,我们拥有[[maybe_unused]]属性。 - metablaster

6
这个问题是在Google搜索中排名前三的问题之一,因此我添加了这个答案,因为我找到了解决方法并想帮助下一个人。

如果你的警告/错误是-Wunused(或其子错误之一)或-Wunused -Werror,那么解决方案是强制转换为void

对于仅有1-Wunused或其子错误之一,您可以将其强制转换为void以禁用警告。这适用于任何编译器和IDE,适用于C和C++。

1注意1:请参阅gcc文档这里,例如,获取这些警告的列表,然后在其中搜索短语“所有上述-Wunused选项组合”并查找主要-Wunused警告及其子警告。 -Wunused包含的子警告包括:

  • -Wunused-but-set-parameter
  • -Wunused-but-set-variable
  • -Wunused-function
  • -Wunused-label
  • -Wunused-local-typedefs
  • -Wunused-parameter
  • -Wno-unused-result
  • -Wunused-variable
  • -Wunused-const-variable
  • -Wunused-const-variable=n
  • -Wunused-value
  • -Wunused=包含所有-Wunused选项

抑制此警告的方法之一是将数据转换为 void 类型,例如:

// some "unused" variable you want to keep around
int some_var = 7;
// turn off `-Wunused` compiler warning for this one variable
// by casting it to void
(void)some_var;  // <===== SOLUTION! ======

对于C++,这也适用于返回被标记为[[nodiscard]]的变量的函数:

C++属性:nodiscard(自C++17起)
如果在从除了转换为void的废弃值表达式中调用声明为nodiscard的函数或返回枚举或类的函数被值声明为nodiscard,则编译器会建议发出警告。
(来源:https://en.cppreference.com/w/cpp/language/attributes/nodiscard

因此,解决方案是将函数调用转换为void,因为这实际上是将由带有[[nodiscard]]属性的函数返回的值强制转换为void
例如:
// Some class or struct marked with the C++ `[[nodiscard]]` attribute
class [[nodiscard]] MyNodiscardClass 
{
public:
    // fill in class details here
private:
    // fill in class details here
};

// Some function which returns a variable previously marked with
// with the C++ `[[nodiscard]]` attribute
MyNodiscardClass MyFunc()
{
    MyNodiscardClass myNodiscardClass;
    return myNodiscardClass;
}

int main(int argc, char *argv[])
{
    // THE COMPILER WILL COMPLAIN ABOUT THIS FUNCTION CALL
    // IF YOU HAVE `-Wunused` turned on, since you are 
    // discarding a "nodiscard" return type by calling this
    // function and not using its returned value!
    MyFunc();

    // This is ok, however, as casing the returned value to
    // `void` suppresses this `-Wunused` warning!
    (void)MyFunc();  // <===== SOLUTION! ======
}

最后,你也可以使用C++17的[[maybe_unused]]属性:https://en.cppreference.com/w/cpp/language/attributes/maybe_unused


5
不要将代码放在文件顶部(甚至头文件中),而是用#pragma warning (push)#pragma warning (disable)和相应的#pragma warning (pop)将相关代码包裹起来,如此处所示。虽然还有其他选项,包括#pramga warning (once)

3
如果你想禁用“未引用的局部变量”,可以在某个头文件中编写。
template<class T>
void ignore (const T & ) {}

并且使用

catch(const Except & excpt) {
    ignore(excpt); // No warning
    // ...  
} 

3
调用一个函数只是为了抑制警告?为什么不这样做呢:(void)unusedVar; - Nawaz
@Nawaz:我认为(void)unusedVar;不符合C++标准。 - Alexey Malistov
没有参考价值。C++标准。这不是有效的代码。这是什么?表达式?函数调用?typedef?类声明? - Alexey Malistov
3
这是一个值为“无”的表达式。在 C++ 中,你甚至可以使用 static_cast<void>(unusedVar) - Nawaz
3
@Nawaz. Herb Sutter的解释:http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/(注:该链接为英文文章)这篇文章讨论了在编写代码时如何关闭编译器警告,以及什么时候应该这样做。作者提出了一些实用的建议,例如在编写高质量代码时避免使用强制类型转换,并在需要使用时使用更安全的类型转换方式。此外,作者还强调了忽略编译器警告可能会导致程序中存在潜在的错误或安全漏洞的风险。 - Alexey Malistov
3
§5.2.9/4规定,“任何表达式都可以显式转换为类型“cv void.” 表达式的值将被丢弃。” 根据这个规定,你可以写static_cast<void>(unusedVar)static_cast<const void>(unusedVar)static_cast<volatile void>(unusedVar)。所有形式都是有效的。希望这能解决你的疑惑。 - Nawaz

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