Visual C ++では、を使用できます#pragma warning (disable: ...)。また、GCCでは、ファイルごとのコンパイラフラグをオーバーライドできることもわかりました。「次の行」に対して、またはGCCを使用してコードの領域の周りにプッシュ/ポップセマンティクスを使用してこれを行うにはどうすればよいですか?
9 に答える
これはできるようです。追加された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ドキュメントを確認してください。
TL; DR:機能する場合は、回避するか、のような指定子を使用します。__attribute__それ以外の場合は_Pragma。
これは私のブログ記事 SuppressingWarningsin GCCandClangの短いバージョンです。
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
欠点:宣言ベースではなく行ベースで機能するため、ほとんど戦術核兵器です。
_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
欠点:宣言ベースではなく行ベースで機能するため、ほとんど戦術核兵器です。
同様の構文がClangにも存在することに注意してください。
単一ファイルのコマンドラインでの警告の抑制
に次の行を追加して、Makefile特にputsの警告を抑制することができます。
CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
puts.o: CPPFLAGS+=-Wno-unused-parameter
これは、特定のケースではおそらく望ましくありませんが、同様の状況にある他の読者に役立つ可能性があります。
質問はGCCに関するものですが、他のコンパイラや複数のコンパイラでこれを行う方法を探している人にとっては…</ p>
TL; DR
私が書いたパブリックドメインの単一のC/C ++ヘッダーであるHedleyを見てみることをお勧めします。これは、このようなことの多くを実行します。この投稿の最後に、これらすべてに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と同じであり、警告名の多くは同じです(ただし、多くは同じではありません)。 - インテルC++コンパイラー(ICC):MSVC構文を使用しますが、警告番号はまったく異なることに注意してください。例:
#pragma warning(disable:1478 1786)。 - PGI / Nvidia:
diag_suppressプラグマがあります:#pragma diag_suppress 1215,1444。すべての警告数が20.7に1つ増えたことに注意してください(最初のNvidia HPCリリース)。 - TI(CCS):
diag_suppressPGIと同じ構文(ただし警告番号が異なる!)のプラグマがあります。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)
- C:
- IAR:
diag_suppressPGIやTIと同様に使用しますが、構文は異なります。警告番号のいくつかは同じですが、私の他の人は異なっています:#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
プッシュとポップ
多くのコンパイラは、警告をスタックにプッシュおよびポップする方法もサポートしています。たとえば、これにより、1行のコードに対する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 - Clang:
#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など)では、プッシュ/ポッププラグマは関数の外にある必要がありました。
残酷な詳細を隠す
ほとんどのコンパイラでは、 C99_Pragmaで導入されたを使用してマクロの背後にあるロジックを隠すことができます。非C99モードでも、ほとんどのコンパイラは;をサポートしています。大きな例外はMSVCで、これには異なる構文の独自のキーワードがあります。標準は文字列を取りますが、Microsoftのバージョンは取りません:_Pragma__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
そして、マクロ定義のすべての醜いバージョンチェックを隠します。
簡単な方法:ヘドリー
コードをクリーンに保ちながら、このようなことを移植可能に行う方法の仕組みを理解したので、私のプロジェクトの1つである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が実行できるすべての警告を無効にすることもできませんが、うまくいけば、あなたはその考えを理解するでしょう。
#pragma GCC diagnostic ignored "-Wformat"
「-Wformat」を警告フラグの名前に置き換えます。
AFAIKこのオプションにプッシュ/ポップセマンティクスを使用する方法はありません。
使用する:
#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キーワードを参照してください。
この種のプラグマをGCCに使用するには、少なくともバージョン4.02が必要ですが、MSVCとClangのバージョンについてはよくわかりません。
GCCのプッシュポッププラグマ処理が少し壊れているようです。警告を再度有効にすると、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
GCCスタイルでは、警告を黙らせるのではなく、通常、標準のC構文または__attribute__拡張機能を使用して、コンパイラーに意図を詳しく伝えます。
たとえば、条件として使用される割り当てに関する警告は、割り当てを括弧で囲むことによって、つまりif ((p=malloc(cnt)))の代わりに抑制されif (p=malloc(cnt))ます。
未使用の関数の引数に関する警告は、私が覚えていない奇妙な__attribute__ことや、自己割り当てなどによって抑制できます。
しかし、一般的に私は、正しいコードで発生することに対して警告を生成する警告オプションをグローバルに無効にすることを好みます。
これを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
参考のために公式ドキュメントを参照してください。