数行のコードでGCC警告を無効にする方法


220

Visual C ++では、を使用できます#pragma warning (disable: ...)。また、GCCではファイルごとのコンパイラフラグを上書きできることもわかりました。これを「次の行」に、またはGCCを使用してコードの領域の周りにプッシュ/ポップセマンティクスで行うにはどうすればよいですか?


1
gccで特定の警告無効にする可能性のある重複-おっと、実際には、その質問自体はだまされています(しかし閉じられていません)。それはたまたま「関連」の下に現れたものです。とにかく、これはSOで何度も尋ねられて答えられました。
タイラーマクヘンリー

1
@paxdiablo:私はその逆をやっている。警告レベルを非常に高く設定しましたが、問題がないことを確認した警告を1行ずつ押しつぶしたいと思います。
マットジョイナー2010

4
@Tyler McHenry:注意深くチェックすると、リンクされた質問にファイルごとの解決策が含まれていることに気付くかもしれません。正確には、私が自分の質問で不十分であると述べました(リンクを盗んだことさえあります)。
マットジョイナー2010

6
@paxdiablo、コンパイラーは誤検知を提供します。-Werrorを使用してコンパイルしたいが、これらの誤検知によってビルドがブロックされないようにする場合があります。特別なケースを無効にし、その理由をコメントすることは、場合によっては理にかなっています。これが便利な他のケースもあります-コードを生成するために、簡単に実行および変更することができない無害な警告を生成する自動生成コードなどですが、その場合、ファイルごとに無効にすることのほうが可能性が高くなりますソリューション。
ideasman42

回答:


221

これは実行できるようです。追加された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 */

14
1つとpush2つpopのs- push最初に別のs が不足している可能性がありますか?
abyss.7 2012年

37
"#pragma GCC diagnostic push #pragma GCC diagnostic pop GCCに各プッシュの診断の状態を記憶させ、各ポップでそのポイントに復元します。ポップに一致するプッシュがない場合、コマンドラインオプションが復元されます。 」-GCC
bobpaul

11
参考までに、gccバージョン4.4.3はエラー/警告/無視をサポートしていますが、プッシュ/ポップはサポートしていません
フランクスター

12
診断プッシュ/ポップ機能を備えたGCCの最初のバージョンはGCC 4.6.4です。これは、GCCドキュメントの
調べて判別しました

5
残念ながら、これは実際には機能しません。場合によっては、より多くの警告が生成されます。あるいは、もっと正確には、GCC 4.7から5.1までは実際には機能しません。たとえば、GCCは警告を停止する「プラグマGCC診断」を尊重していません
jww 2015


31

TL; DR:のような、それが動作する場合、回避、または使用指定子__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)であるため、コンパイルされません。

次の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特にputに関する警告を抑制できます。

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

.PHONY: all
all: puts

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

これは、特定のケースではおそらく必要ありませんが、同様の状況にある他の読み取りに役立つ場合があります。


2
re:引数に名前を付けないことによりimproving the source、mainの宣言をtoに変更することもint main(int, const char* argv[]) { ... }できます。使用しないことをコンパイラに伝えます。
ジェシーチザム2018

1
@JesseChisholmは、関数定義でパラメーター名を省略することはできません。ISO / IEC9899の6.9.1機能definintionsを参照してください、§5、正しくので、コードがによって拒否されるだろう「宣言子は、パラメータの型のリストが含まれている場合は、各パラメータの宣言は、識別子[...]含まなければならない」gccなどをclang
Christian Hujer、

1
別のパターンは、変数をvoidにキャストするだけです。実際、私はプロジェクトで次のマクロを見ました:#define UNUSED(x) ((void)x)警告を黙らせるために使用されます。ReactOSにあったと思いますか?
Paul Stelian

1
この後、バックスラッシュは必要ないと思いますか?と思う_Pragma("GCC diagnostic pop") \ だけ_Pragma("GCC diagnostic pop")です。
ガブリエルステープルズ

1
@GabrielStaples正解です。気づいていただきありがとうございます。回答を更新しました。
クリスチャンHujer

20
#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

これらの種類のプラグマをgccに使用するには、少なくともバージョン4.02が必要です。バージョンに関するmsvcとclangについては不明です。

gccのpush popプラグマ処理が少し壊れているようです。警告を再度有効にしても、DISABLE_WARNING / ENABLE_WARNINGブロック内にあったブロックの警告は引き続き表示されます。gccの一部のバージョンでは機能しますが、一部のバージョンでは機能しません。


3
あなたda real MVP
zeboidlund

19
#pragma GCC diagnostic ignored "-Wformat"

「-Wformat」を警告フラグの名前に置き換えます。

私の知る限り、このオプションにプッシュ/ポップセマンティクスを使用する方法はありません。


4
残念ながら、これは実際には機能しません。場合によっては、より多くの警告が生成されます。あるいは、もっと正確には、GCC 4.7から5.1までは実際には機能しません。たとえば、GCCは警告を停止する「プラグマGCC診断」を尊重していません
jww 2015

6

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

2
これは、gccのシステム ディレクトリで処理する方がよいでしょうか。
赤XIII

@RedXIII-はい、そのようなディレクトリのリストを作成し、gccコマンドラインで指定できる場合、これはオプションです。ただし、コンパイラーはパイプラインの深部で何度も呼び出されるか、他の誰かがコードをコンパイルする方法をあまり制御できません。これらの場合、上記の方がおそらくより良い解決策です。
Shital Shah、

5

問題はGCCに関するものであることはわかっていますが、他のコンパイラや複数のコンパイラでこれを行う方法を探している人のために…

TL; DR

Hedleyをご覧になるとよいでしょう。Hedleyは、私が書いた、パブリックドメインの単一のC / C ++ヘッダーであり、この処理を数多く実行します。この記事の最後に、Hedleyを使用するための簡単なセクションを配置します。

警告を無効にする

#pragma warning (disable: …) ほとんどのコンパイラで同等のものがあります:

  • MSVC: #pragma warning(disable:4996)
  • GCC:#pragma GCC diagnostic ignored "-W…"省略記号は警告の名前です。例えば#pragma GCC diagnostic ignored "-Wdeprecated-declarations
  • 打ち鳴らします:#pragma clang diagnostic ignored "-W…"。構文は基本的にGCCと同じであり、警告名の多くは同じです(多くは同じではありません)。
  • インテルCコンパイラ:MSVC構文を使用しますが、警告番号はまったく異なることに注意してください。例:#pragma warning(disable:1478 1786)
  • PGI:diag_suppressプラグマがあります:#pragma diag_suppress 1215,1444
  • TI:diag_suppressPGIと同じ構文(ただし警告番号が異なる!)のプラグマがあります。pragma diag_suppress 1291,1718
  • Oracle Developer Studio(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: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

XL C / C ++の新しいバージョンやarmclangなどのclangおよびclangベースのコンパイラーの場合、__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+(VS 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は、C99で導入されたを使用して、マクロの背後にロジックを隠すことができます。C99以外のモードでも、ほとんどのコンパイラはをサポートしてい_Pragmaます。大きな例外はMSVCです。これには、__pragma構文が異なる独自のキーワードがあります。標準_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

また、マクロ定義内の醜いバージョンチェックをすべて隠します。

簡単な方法:ヘドリー

コードをクリーンに保ちながら、このようなことをポータブルに行う方法のメカニズムを理解したところで、私のプロジェクトの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、およびその他の可能性のある非推奨関数の呼び出しに関する警告を無効にします(ヘドリーを更新するときに、おそらくこの回答を更新する必要はありません)。また、動作が確認されていないコンパイラでは、マクロは前処理されて何も処理されないため、コードはどのコンパイラでも引き続き機能します。もちろんHEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED、Hedleyが知っている警告はこれだけではありません。Hedleyができるすべての警告を無効にすることもできませんが、うまくいけばアイデアがわかります。


3

警告を沈黙させるのではなく、gccスタイルは通常、標準のC構文または__attribute__拡張機能を使用して、コンパイラーに意図を詳しく伝えます。たとえば、条件として使用される割り当てに関する警告は、割り当てを括弧の中に入れることで、つまりのif ((p=malloc(cnt)))代わりに抑制されif (p=malloc(cnt))ます。未使用の関数の引数に関する警告__attribute__は、覚えられない奇妙な方法や自己割り当てなどによって抑制できます。しかし、一般的には、正しいコードで発生することに対して警告を生成する警告オプションをグローバルに無効にすることを優先します。


2
多分そう。私の意図は、一般的なケースパターンを証明することではなく、警告抑制に​​関するgccの哲学についての観察です。
R .. GitHub ICEのヘルプ停止

コンパイラは、括弧が追加されたw / r / t警告の動作が異なります!??!?? !!!! うわー!それは予想外です。
Jason S

1
@JasonS括弧はコンパイラの動作に関する警告を変更せず、ステートメントのセマンティクスを変更します。余分な括弧は、コンパイラに割り当てを終了させ、その最終的な値を式として保持します。これは警告に値しません。明確にしたい場合if ((p=malloc(cnt)) != NULL) ...は、コンパイラが背後で行っていることをそのまま使用できます。
ジェシーチザム2018

@JesseChisholm:あなたの説明は正確ではないと思います。
R .. GitHub ICEのヘルプを停止する

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を参照してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.