在Visual C++中,可以使用 #pragma warning (disable: ...)
。我也发现在GCC中,可以使用针对每个文件覆盖编译器标志。如何在使用GCC时在“下一行”或使用push/pop语义在代码区域周围来实现这一点?
在Visual C++中,可以使用 #pragma warning (disable: ...)
。我也发现在GCC中,可以使用针对每个文件覆盖编译器标志。如何在使用GCC时在“下一行”或使用push/pop语义在代码区域周围来实现这一点?
看起来可以使用这种方法。我无法确定它是在哪个版本的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 */
push
和两个 pop
- 开始可能缺少另一个 push
? - abyss.7总的来说,这是一个暂时禁用警告的示例:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
write(foo, bar, baz);
#pragma GCC diagnostic pop
您可以查看GCC文档中有关诊断预处理指令的详细信息。
gcc-4.9
却完全忽略了这一行。 - Aleksei PetrenkoTL;DR: 如果可以的话,避免使用,或者使用特定说明符比如_Noreturn
、[[nodiscard]]
、__attribute__
,否则使用_Pragma
。
这是我个人博客文章在GCC和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
)。[[maybe_unused]]
。__attribute__
。_Pragma
。#pragma
。首先应该检查源代码是否可以改进以消除警告。在这种情况下,我们不想仅仅因为这个原因改变算法,因为argc
与!*argv
(最后一个元素后的NULL
)是多余的。
[[maybe_unused]]
#include <stdio.h>
int main([[maybe_unused]] int argc, const char *argv[])
{
while (*++argv) puts(*argv);
return 0;
}
[[maybe_unused]]
。属性是C2x的新功能。到目前为止,C2x定义了四个属性:[[deprecated]]
、[[fallthrough]]
、[[maybe_unused]]
和[[nodiscard]]
。
__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
指令则不可能。_Pragma
运算符是在C99中引入的。
#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
Makefile
中,以针对puts特别抑制警告:CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
puts.o: CPPFLAGS+=-Wno-unused-parameter
这可能不是你特定情况下想要的,但它可能会帮助其他处于类似情况的读者。
#define UNUSED(x) ((void)x)
用于消除警告。我想这是在 ReactOS 中使用的。 - Paul Stelian__attribute__
语法的工作方式非常巧妙,它聪明地使用双括号 ((
))
,因此,如果你的编译器不理解它,你可以定义 #define __attribute__(x)
,这些括号就会全部消失。 - doug65536_Pragma()
风格而不是 #pragma
风格,现在我终于找到了!你可能想把这个加入到你的答案中:如果你想把这些调用放在宏定义内部,那么你必须使用 _Pragma()
风格!这是因为你不能从宏定义内部进行以 #
开头的预处理器调用,因为 #
字符在宏定义内部有特殊含义(它是字符串化字符),不能像那样使用。 - Gabriel StaplesUNREFERENCED_PARAMETER
这种方式。鉴于ReactOS受到Windows的很大“启发”,我认为可能是从那里借鉴过来的。虽然这并不是什么难以想象的事情。 - undefined我知道问题是关于GCC的,但对于那些想在其他和/或多个编译器中执行此操作的人...
你可能想看看Hedley,这是一个我编写的公共领域单一C/C++头文件,它可以为您完成很多工作。我将在本文末尾放置有关如何使用Hedley进行所有这些操作的快速部分。
#pragma warning (disable: …)
在大多数编译器中都有相应的等价物:
#pragma warning(disable:4996)
#pragma GCC diagnostic ignored "-W..."
,其中省略号是警告的名称;例如:#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
.#pragma clang diagnostic ignored "-W..."
。语法基本与GCC相同,许多警告名称也相同(但许多不同)。#pragma warning(disable:1478 1786)
。diag_suppress
指示: #pragma diag_suppress 1215,1444
。注意,所有警告编号在20.7中增加了一次(第一个Nvidia HPC版本)。diag_suppress
指示:pragma diag_suppress 1291,1718
error_messages
指示。令人恼火的是,C和C++编译器的警告不同。这两个禁用基本相同的警告:
#pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
#pragma error_messages(off,symdeprecated,symdeprecated2)
diag_suppress
,但语法不同。一些警告编号相同,但其他警告编号已经分歧:#pragma diag_suppress=Pe1444,Pe1215
#pragma warn(disable:2241)
对于大多数编译器而言,在尝试禁用它之前检查编译器版本通常是个好主意,否则你只会触发另一个警告。例如,GCC 7添加了对-Wimplicit-fallthrough
警告的支持,因此如果你关心GCC 7之前的版本,应该做如下处理:
#if defined(__GNUC__) && (__GNUC__ >= 7)
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
对于基于Clang的编译器,例如较新版本的XL C/C++和armclang,您可以使用__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
所以你可以更轻松地使用__has_warning
。Clang甚至在他们的手册中建议类似于__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
接下来你可以做像{{这样的事情}}
#if MY_HAS_WARNING(warning)
# pragma clang diagnostic ignored "-Wimplicit-fallthrough"
#elif defined(__GNUC__) && (__GNUC__ >= 7)
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
许多编译器还支持将警告推入和弹出堆栈的方法。例如,以下代码将在GCC上禁用一个警告一行,然后将其返回到先前的状态:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
call_deprecated_function();
#pragma GCC diagnostic pop
_Pragma
来隐藏宏背后的逻辑。即使在非C99模式下,大多数编译器也支持_Pragma
;唯一的例外是具有不同语法的自己的__pragma
关键字的MSVC。标准的_Pragma
需要一个字符串,Microsoft的版本则不需要。#if defined(_MSC_VER)
# define PRAGMA_FOO __pragma(foo)
#else
# define PRAGMA_FOO _Pragma("foo")
#endif
PRAGMA_FOO
一旦预处理后,大致相当于{{某个内容}}。
#pragma foo
这让我们能够创建宏,以便我们可以编写如下的代码
MY_DIAGNOSTIC_PUSH
MY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated_function();
MY_DIAGNOSTIC_POP
并且在宏定义中隐藏所有丑陋的版本检查。
现在你已经理解了如何在保持代码清洁的同时以可移植的方式完成这样的事情的机制,你就明白了我的一个项目Hedley的作用。你可以只包含Hedley(它是一个单一的公共领域C/C++头文件),而不必深入研究大量文档和/或安装尽可能多的编译器版本进行测试。例如:
#include "hedley.h"
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP
将禁用有关在GCC、Clang、ICC、PGI、MSVC、TI、IAR、ODS、Pelles C以及可能其他编译器上调用已弃用函数的警告(我可能不会在更新Hedley时更新此答案)。而且,在不被认为可以工作的编译器上,宏将被预处理到无处不在,因此您的代码将继续与任何编译器一起工作。当然,HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
不是 Hedley 所知道的唯一警告,禁用警告也不是 Hedley 可以做的全部,但希望您能理解。
使用:
#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
可以使用以下方式进行调用:
DISABLE_WARNING(unused-variable,unused-variable,42)
[.... some code with warnings in here ....]
ENABLE_WARNING(unused-variable,unused-variable,42)
#pragma GCC diagnostic ignored "-Wformat"
将"-Wformat"替换为您的警告标志名称。
据我所知,无法使用push/pop语义来处理此选项。
我曾经遇到过外部库文件的问题,比如像 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 a problem goes here
#include <ros/ros.h>
#include <sensor_msgs/LaserScan.h>
// Restore compiler switches
#pragma GCC diagnostic pop
以下是在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
参考官方文档。
if ((p=malloc(cnt)) != NULL) ...
,因为这就是编译器在幕后所做的。 - Jesse Chisholm