在Visual c++中,可以使用#pragma warning (disable:…)我还发现,在GCC中,您可以覆盖每个文件编译器标志。我怎么能做到这一点为“下一行”,或与推/弹出语义周围的代码区域使用GCC?
#pragma GCC diagnostic ignored "-Wformat"
将"-Wformat"替换为警告标志的名称。
AFAIK,这个选项没有办法使用push/pop语义。
GCC风格通常不是关闭警告,而是使用标准C结构或__attribute__扩展名来告诉编译器更多关于你的意图的信息。
例如,关于将赋值用作条件的警告通过将赋值放在括号中来抑制,即if ((p=malloc(cnt))而不是if (p=malloc(cnt))。
关于未使用函数参数的警告可以通过一些奇怪的__attribute__我永远都记不住,或者通过自赋值等来抑制。
但一般来说,我更喜欢全局禁用任何警告选项,这些选项会为正确的代码中发生的事情生成警告。
这似乎是可以做到的。我无法确定它添加的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 */
这是一个暂时禁用警告的例子:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-result"
write(foo, bar, baz);
#pragma GCC diagnostic pop
您可以查看GCC诊断指南文档以获得更多详细信息。
Use:
#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)
参见7 Pragmas,通过Pragmas和Pragma指令控制诊断,以及__pragma和_Pragma关键字了解更多细节。
你至少需要4.02版本才能使用GCC的这些代码,我不确定MSVC和Clang的版本。
看起来GCC的push pop pragma处理有点坏。如果再次启用警告,仍然会得到DISABLE_WARNING/ENABLE_WARNING块内部的警告。对于GCC的某些版本,它可以工作,而对于某些版本,它不能。
我有同样的问题与外部库,如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
参考官方文件。
TL;DR:如果它工作,避免,或使用像_Noreturn, [[nodiscard]], __attribute__这样的说明符,否则_Pragma。
这是我博客文章的一个简短版本 GCC和Clang中的抑制警告。
考虑下面的Makefile,
CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
构建下面的put .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__((未使用))放在宏中。
_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 directive。
我们可以更改源代码来抑制对代码区域(通常是整个函数)的警告:
#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
缺点:它几乎是一个战术核武器,因为它是基于行而不是基于声明的。
注意,Clang中也存在类似的语法。
对单个文件取消命令行上的警告
我们可以在Makefile中添加下面这行代码来抑制针对看跌期权的警告:
CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
puts.o: CPPFLAGS+=-Wno-unused-parameter
在你的特定情况下,这可能不是你想要的,但它可能会帮助其他有类似情况的读者。
我知道这个问题是关于GCC的,但是对于那些寻找如何在其他和/或多个编译器中做到这一点的人来说……
博士TL;
你可能想看看Hedley,这是我写的一个公共域的C/ c++头文件,它为你做了很多这些事情。我将在这篇文章的最后简要介绍如何使用Hedley。
禁用警告
#pragma warning (disable:…)在大多数编译器中都有等价的:
MSVC: #pragma warning(disable:4996) GCC: #pragma GCC diagnostic ignored "-W…" where the ellipsis is the name of the warning; e.g., #pragma GCC diagnostic ignored "-Wdeprecated-declarations. Clang: #pragma clang diagnostic ignored "-W…". The syntax is basically the same as GCC's, and many of the warning names are the same (though many aren't). Intel C++ Compiler (ICC): Use the MSVC syntax, but keep in mind that warning numbers are totally different. Example: #pragma warning(disable:1478 1786). PGI/Nvidia: There is a diag_suppress pragma: #pragma diag_suppress 1215,1444. Note that all warning numbers increased by one in 20.7 (the first Nvidia HPC release). TI (CCS): There is a diag_suppress pragma with the same syntax (but different warning numbers!) as PGI: pragma diag_suppress 1291,1718 Oracle Developer Studio (ODS) (suncc): there is an error_messages pragma. Annoyingly, the warnings are different for the C and C++ compilers. Both of these disable basically the same warnings: C: #pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS) C++: #pragma error_messages(off,symdeprecated,symdeprecated2) IAR: also uses diag_suppress like PGI and TI, but the syntax is different. Some of the warning numbers are the same, but I others have diverged: #pragma diag_suppress=Pe1444,Pe1215 Pelles C: similar to MSVC, though again the numbers are different #pragma warn(disable:2241)
对于大多数编译器,在尝试禁用它之前检查编译器版本通常是一个好主意,否则您将最终触发另一个警告。例如,GCC 7增加了对-Wimplicit-fallthrough警告的支持,所以如果你关心7之前的GCC,你应该这样做
#if defined(__GNUC__) && (__GNUC__ >= 7)
# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#endif
对于Clang和基于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
当然,在编译器之间并没有很多关于语法的一致意见:
GCC 4.6+: #前兆诊断推/ /前兆诊断GCC诊断流行 俚语,俚语诊断,俚语诊断,俚语诊断 情报13+,也许更早: MSVC 15+(视觉工作室9.0 / 2008): ARM 5.6+: #pragma推/ #pragma pop TI 8.1+: #pragma diag_push / #pragma diag_pop Pelles c2.90 +(也许更早):
如果没记错的话,对于一些非常旧的GCC版本(比如3。x, IIRC)的推送/弹出指令必须在函数之外。
隐藏血腥的细节
对于大多数编译器来说,可以使用_Pragma隐藏宏背后的逻辑,这是C99中引入的。即使在非c99模式下,大多数编译器也支持_Pragma;最大的例外是MSVC,它有自己的__pragma关键字,但语法不同。标准的_Pragma接受一个字符串,而微软的版本不接受:
#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所做的事情。而不是挖掘大量的文档和/或安装尽可能多的编译器版本来测试,你只需要包含Hedley(它是一个单一的公共域C/ c++头文件),就可以完成它了。例如:
#include "hedley.h"
HEDLEY_DIAGNOSTIC_PUSH
HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
call_deprecated();
HEDLEY_DIAGNOSTIC_POP
Will disable the warning about calling a deprecated function on GCC, Clang, ICC, PGI, MSVC, TI, IAR, ODS, Pelles C, and possibly others (I probably won't bother updating this answer as I update Hedley). And, on compilers which aren't known to work, the macros will be preprocessed away to nothing, so your code will continue to work with any compiler. Of course HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED isn't the only warning Hedley knows about, nor is disabling warnings all Hedley can do, but hopefully you get the idea.