我知道这个问题是关于 GCC 的,但是对于寻找如何在其他和/或多个编译器中执行此操作的人来说……
TL;DR
您可能想查看Hedley,这是我编写的一个公共域单个 C/C++ 标头,它为您提供了很多这些内容。我将在这篇文章的末尾简要介绍如何使用 Hedley 来完成所有这些工作。
禁用警告
#pragma warning (disable: …) 在大多数编译器中都有等价物:
-
MSVC:
#pragma warning(disable:4996)
- GCC:
#pragma GCC diagnostic ignored "-W…",其中省略号是警告的名称; 例如,#pragma GCC diagnostic ignored "-Wdeprecated-declarations。
-
Clang:
#pragma clang diagnostic ignored "-W…"。语法与 GCC 基本相同,并且许多警告名称相同(尽管很多不同)。
-
Intel C++ Compiler (ICC):使用 MSVC 语法,但请记住警告编号完全不同。示例:
#pragma warning(disable:1478 1786)。
-
PGI/Nvidia:有一个
diag_suppress pragma:#pragma diag_suppress 1215,1444。请注意all warning numbers increased by one in 20.7(第一个 Nvidia HPC 版本)。
-
TI (CCS):有一个
diag_suppress 杂注,其语法与 PGI 相同(但警告编号不同!):pragma diag_suppress 1291,1718
-
Oracle Developer Studio (ODS) (suncc):有一个
error_messages 杂注。令人讨厌的是,C 和 C++ 编译器的警告是不同的。这两个都禁用了基本相同的警告:
- C:
#pragma error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)
- C++:
#pragma error_messages(off,symdeprecated,symdeprecated2)
-
IAR:也像 PGI 和 TI 一样使用
diag_suppress,但语法不同。一些警告数字是相同的,但我其他人已经分歧:#pragma diag_suppress=Pe1444,Pe1215
-
Pelles C:与 MSVC 类似,但数字再次不同
#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+:
#pragma GCC diagnostic push/#pragma GCC diagnostic pop
- 叮当声:
#pragma clang diagnostic push / #pragma diagnostic pop
- Intel 13+(可能更早):
#pragma warning(push) / #pragma warning(pop)
- MSVC 15+ (Visual Studio 9.0 / 2008):
#pragma warning(push) / #pragma warning(pop)
- ARM 5.6+:
#pragma push/#pragma pop
- TI 8.1+:
#pragma diag_push/#pragma diag_pop
- Pelles C 2.90+(可能更早):
#pragma warning(push) / #pragma warning(pop)
如果没记错的话,对于一些非常旧的 GCC 版本(如 3.x、IIRC),push/pop pragma 必须在函数之外。
隐藏血淋淋的细节
对于大多数编译器,可以使用_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(它是一个单一的公共域 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 所能做的所有禁用警告,但希望您明白这一点。