如何禁用几行代码的GCC警告

时间:2010-07-31 14:41:40

标签: c gcc compiler-warnings pragma

在Visual C ++中,可以使用#pragma warning (disable: ...)。我也发现在GCC你可以override per file compiler flags。我如何为“下一行”执行此操作,或者使用GCC在代码区域内使用推/弹语义?

9 个答案:

答案 0 :(得分:194)

看来这是can be done。我无法确定它添加的GCC版本,但它是在2010年6月之前的某个时间。

以下是一个例子:

#pragma GCC diagnostic error "-Wuninitialized"
    foo(a);         /* error is given for this one */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
    foo(b);         /* no diagnostic for this one */
#pragma GCC diagnostic pop
    foo(c);         /* error is given for this one */
#pragma GCC diagnostic pop
    foo(d);         /* depends on command line options */

答案 1 :(得分:91)

为了解决所有问题,这是暂时禁用警告的示例:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

您可以查看GCC documentation on diagnostic pragmas了解详情。

答案 2 :(得分:19)

TL; DR :如果有效,请避免或使用__attribute__等说明符,否则为_Pragma

这是我博客文章的简短版本 Suppressing Warnings in GCC and Clang

考虑以下Makefile

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

用于构建以下puts.c源代码

#include <stdio.h>

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

它不会编译,因为argc未使用,设置为硬核(-W -Wall -pedantic -Werror)。

你可以做5件事:

  • 尽可能改进源代码
  • 使用声明说明符,例如__attribute__
  • 使用_Pragma
  • 使用#pragma
  • 使用命令行选项。

改善来源

第一次尝试应检查是否可以改进源代码以消除警告。在这种情况下,我们不希望仅因此更改算法,因为argc!*argvNULL在最后一个元素之后)是多余的。

使用声明说明符,如__attribute__

#include <stdio.h>

int main(__attribute__((unused)) int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}

如果您很幸运,该标准会为您的情况提供说明符,例如_Noreturn

__attribute__是专有的GCC扩展(由Clang和其他一些编译器支持,如armcc),许多其他编译器都不会理解。如果您想要可移植代码,请将__attribute__((unused))放在宏中。

_Pragma运算符

_Pragma可用作#pragma的替代。

#include <stdio.h>

_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")

int main(int argc, const char *argv[])
{
    while (*++argv) puts(*argv);
    return 0;
}
_Pragma("GCC diagnostic pop") \

_Pragma运算符的主要优点是可以将其放在宏中,这对于#pragma指令是不可能的。

下行:这几乎是一个战术核武器,因为它基于行而不是基于声明。

{C}中引入了_Pragma运算符。

#pragma指令。

我们可以更改源代码以禁止代码区域的警告,通常是整个函数:

#include <stdio.h>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(int argc, const char *argv[])
{
    while (*++argc) puts(*argv);
    return 0;
}
#pragma GCC diagnostic pop

下行:这几乎是一个战术核武器,因为它是基于行的而不是声明-baesd。

在命令行上禁止单个文件的警告

我们可以将以下行添加到Makefile以禁止专门针对puts的警告:

CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror

.PHONY: all
all: puts

puts.o: CPPFLAGS+=-Wno-unused-parameter

在您的特定情况下,这可能不是您想要的,但它可能有助于处于类似情况的其他读取。

答案 3 :(得分:16)

#pragma GCC diagnostic ignored "-Wformat"

将“-Wformat”替换为警告标志的名称。

AFAIK无法使用此选项的推/弹语义。

答案 4 :(得分:16)

#define DIAG_STR(s) #s
#define DIAG_JOINSTR(x,y) DIAG_STR(x ## y)
#ifdef _MSC_VER
#define DIAG_DO_PRAGMA(x) __pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(warning(x))
#else
#define DIAG_DO_PRAGMA(x) _Pragma (#x)
#define DIAG_PRAGMA(compiler,x) DIAG_DO_PRAGMA(compiler diagnostic x)
#endif
#if defined(__clang__)
# define DISABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,push) DIAG_PRAGMA(clang,ignored DIAG_JOINSTR(-W,clang_option))
# define ENABLE_WARNING(gcc_unused,clang_option,msvc_unused) DIAG_PRAGMA(clang,pop)
#elif defined(_MSC_VER)
# define DISABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,push) DIAG_DO_PRAGMA(warning(disable:##msvc_errorcode))
# define ENABLE_WARNING(gcc_unused,clang_unused,msvc_errorcode) DIAG_PRAGMA(msvc,pop)
#elif defined(__GNUC__)
#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 406
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,push) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,pop)
#else
# define DISABLE_WARNING(gcc_option,clang_unused,msvc_unused) DIAG_PRAGMA(GCC,ignored DIAG_JOINSTR(-W,gcc_option))
# define ENABLE_WARNING(gcc_option,clang_option,msvc_unused) DIAG_PRAGMA(GCC,warning DIAG_JOINSTR(-W,gcc_option))
#endif
#endif

这应该适用于gcc,clang和msvc

可以用例如:

来调用
DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)

有关详细信息,请参阅https://gcc.gnu.org/onlinedocs/cpp/Pragmas.htmlhttp://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmashttps://msdn.microsoft.com/de-DE/library/d9x1s805.aspx

至少需要4.02版本才能为gcc使用这种编译指示,不确定msvc和clang版本。

看起来gcc的push pop pragma处理有点破碎。如果再次启用警告,仍会收到DISABLE_WARNING / ENABLE_WARNING块内的块的警告。对于某些版本的gcc,它可以工作,但有些版本没有。

答案 5 :(得分:5)

我对ROS头等外部库也有同样的问题。我喜欢在CMakeLists.txt中使用以下选项进行更严格的编译:

set(CMAKE_CXX_FLAGS "-std=c++0x -Wall -Wextra -Wstrict-aliasing -pedantic -Werror -Wunreachable-code ${CMAKE_CXX_FLAGS}")

然而,这样做会导致外部包含的库中的所有类型的迂腐错误。解决方案是在包含外部库并重新启用之前禁用所有迂腐警告:

//save compiler switches
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"

//Bad headers with problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>

//restore compiler switches
#pragma GCC diagnostic pop

答案 6 :(得分:3)

gcc样式通常使用标准C构造或__attribute__扩展来告诉编译器更多关于您的意图,而不是使警告静音。例如,通过将赋值括在括号中来抑制关于用作条件的赋值的警告,即if ((p=malloc(cnt)))而不是if (p=malloc(cnt))。关于未使用的函数参数的警告可以通过我永远不会记住的一些奇怪的__attribute__或者通过自我赋值等来抑制。但是通常我更喜欢全局禁用任何警告选项,该警告选项会对正确代码中发生的事情生成警告

答案 7 :(得分:3)

对于那些发现此页面寻找在IAR中执行此操作的方法的人,请尝试以下操作:

#pragma diag_suppress=Pe177
void foo1( void )
{
   /* The following line of code would normally provoke diagnostic 
      message #177-D: variable "x" was declared but never referenced.
      Instead, we have suppressed this warning throughout the entire 
      scope of foo1(). 
   */
   int x;
}
#pragma diag_default=Pe177

请参阅http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472m/chr1359124244797.html以供参考。

答案 8 :(得分:2)

我知道问题是关于GCC的,但是对于正在寻找如何在其他和/或多个编译器中执行此操作的人来说……

TL; DR

您可能想看看Hedley,它是我编写的一个公共域单个C / C ++头文件,它为您做这些事情 lot 。在本文的结尾,我将快速介绍一下如何使用Hedley。

禁用警告

#pragma warning (disable: …)在大多数编译器中具有等效功能:

  • MSVC:#pragma warning(disable:4996)
  • GCC:#pragma GCC diagnostic ignored "-W…",其中省略号是警告的名称; 例如#pragma GCC diagnostic ignored "-Wdeprecated-declarations
  • c:#pragma clang diagnostic ignored "-W…"。语法基本上与GCC相同,并且许多警告名称相同(尽管很多不是)。
  • Intel C编译器:使用MSVC语法,但请记住警告号完全不同。例如:#pragma warning(disable:1478 1786)
  • PGI:存在diag_suppress编译指示:#pragma diag_suppress 1215,1444
  • TI:diag_suppress与PGI的语法相同(但警告号不同!)
  • Oracle Developer Studio(suncc):有一个pragma diag_suppress 1291,1718编译指示。令人讨厌的是,对于C和C ++编译器,警告是不同的。这些都禁用基本上相同的警告:
    • C:error_messages
    • C ++:#pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
  • IAR:也像PGI和TI一样使用#pragma error_messages(off,symdeprecated,symdeprecated2),但是语法不同。一些警告数字是相同的,但其他一些则有所不同:diag_suppress
  • C球:类似于MSVC,但数字再次不同#pragma diag_suppress=Pe1444,Pe1215

对于大多数编译器而言,在尝试禁用编译器版本之前通常是一个好主意,否则最终将触发另一个警告。例如,GCC 7添加了对#pragma warn(disable:2241)警告的支持,因此,如果您在7之前关注GCC,则应该执行类似的操作

-Wimplicit-fallthrough

对于clang和基于clang的编译器(例如XL C / C ++的较新版本和armclang),您可以使用#if defined(__GNUC__) && (__GNUC__ >= 7) # pragma GCC diagnostic ignored "-Wimplicit-fallthrough" #endif 宏来检查编译器是否知道特定警告。

__has_warning()

当然,您还必须检查#if __has_warning("-Wimplicit-fallthrough") # pragma clang diagnostic ignored "-Wimplicit-fallthrough" #endif 宏是否存在:

__has_warning()

您可能会想做类似的事情

#if defined(__has_warning)
#  if __has_warning("-Wimplicit-fallthrough")
#    pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#  endif
#endif

因此,您可以更轻松地使用#if !defined(__has_warning) # define __has_warning(warning) #endif 。 Clang甚至在他们的手册中为__has_warning宏提出了类似的建议。 不这样做。其他代码可能会检查__has_builtin()并在检查编译器版本(如果不存在)时退回去,如果定义__has_warning,则会破坏其代码。正确的方法是在名称空间中创建宏。例如:

__has_warning

然后您可以做类似的事情

#if defined(__has_warning)
#  define MY_HAS_WARNING(warning) __has_warning(warning)
#else
#  define MY_HAS_WARNING(warning) (0)
#endif

推动和弹出

许多编译器还支持将警告推送和弹出到堆栈上的方法。例如,这将在GCC上针对一行代码禁用警告,然后将其恢复为之前的状态:

#if MY_HAS_WARNING(warning)
#  pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
#  pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif

当然,编译器之间在语法上并没有很多共识:

  • GCC 4.6 +:#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated" call_deprecated_function(); #pragma GCC diagnostic pop / #pragma GCC diagnostic push
  • c语:#pragma GCC diagnostic pop / #pragma clang diagnostic push
  • Intel 13+(可能更早):#pragma diagnostic pop / #pragma warning(push)
  • MSVC 15+(VS 9.0 / 2008):#pragma warning(pop) / #pragma warning(push)
  • ARM 5.6+:#pragma warning(pop) / #pragma push
  • TI 8.1+:#pragma pop / #pragma diag_push
  • Pelles C 2.90+(可能更早):#pragma diag_pop / #pragma warning(push)

如果有内存,则对于某些非常老版本的GCC(例如3.x,IIRC),push / pop编译指示必须在函数的 之外。

隐藏血腥细节

对于大多数编译器而言,可以使用C99中引入的#pragma warning(pop)将逻辑隐藏在宏后面。即使在非C99模式下,大多数编译器也支持_Pragma。最大的例外是MSVC,它具有自己的_Pragma关键字和不同的语法。标准__pragma带有字符串,Microsoft的版本没有:

_Pragma

经过预处理,大致等同于

#if defined(_MSC_VER)
#  define PRAGMA_FOO __pragma(foo)
#else
#  define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO

这使我们可以创建宏,以便我们可以编写类似的代码

#pragma foo

并在宏定义中隐藏所有难看的版本检查。

简单的方法:赫德利

现在,您了解了如何在保持代码干净的同时可移植地执行此类操作的机制,您了解了Hedley我的项目之一。您不必包括大量的文档和/或安装尽可能多的编译器版本以进行测试,而只需包含Hedley(它是单个公共域C / C ++标头)即可完成。例如:

MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP

将禁用有关在GCC,clang,ICC,PGI,MSVC,TI,IAR,ODS,Pelles以及其他可能上调用过时函数的警告(在更新Hedley时,我可能不会费心更新此答案)。而且,在未知的编译器上,宏将被预处理为零,因此您的代码将继续与任何编译器一起使用。当然,#include "hedley.h" HEDLEY_DIAGNOSTIC_PUSH HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED call_deprecated(); HEDLEY_DIAGNOSTIC_POP 并不是Hedley知道的唯一警告,也不是禁用Hedley可以做的所有警告,但是希望您能理解。