web-dev-qa-db-ja.com

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

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

192
Matt Joiner

このように見えます できます 。追加された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 */
199
Matt Joiner

すべてを無効にするために、これは警告を無効にするtemporarilyの例です。

#pragma GCC diagnostic Push
#pragma GCC diagnostic ignored "-Wunused-result"
    write(foo, bar, baz);
#pragma GCC diagnostic pop

詳細については、 診断プラグマに関するGCCドキュメント を確認してください。

94
Ian Pilcher

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!*argv(最後の要素の後のNULL)と冗長であるため、そのためだけにアルゴリズムを変更する必要はありません。

__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

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

22
Christian Hujer
#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-pragmas and https://msdn.Microsoft.com/de-DE/library/d9x1s805.aspx 詳細については

これらの種類のプラグマをgccで使用するには、少なくともバージョン4.02が必要です。バージョンに関するmsvcおよびclangについてはわかりません。

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

17
Martin Gerhardy
#pragma GCC diagnostic ignored "-Wformat"

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

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

17
Joe D

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
5
Shital Shah

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

3
R..

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

3
Keron

私は質問がGCCについてであることを知っていますが、他のおよび/または複数のコンパイラでこれを行う方法を探している人のために...

TL; DR

Hedley をご覧ください。これは、私が書いたパブリックドメインの単一のC/C++ヘッダーで、lotを実行します君は。この記事の最後に、これらすべてにHedleyを使用する方法について簡単なセクションを示します。

警告を無効にする

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

  • MSVC:#pragma warning(disable:4996)
  • GCC:#pragma GCC diagnostic ignored "-W…"ここで、省略記号は警告の名前です。 e.g。#pragma GCC diagnostic ignored "-Wdeprecated-declarations
  • clang:#pragma clang diagnostic ignored "-W…"。構文は基本的にGCCと同じであり、警告名の多くは同じです(ただし、多くは同じではありません)。
  • インテルCコンパイラー:MSVC構文を使用しますが、警告番号はまったく異なることに注意してください。例:#pragma warning(disable:1478 1786)
  • PGI:diag_suppressプラグマがあります:#pragma diag_suppress 1215,1444
  • TI:PGIと同じ構文(ただし、警告番号は異なります)のdiag_suppressプラグマがあります: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:PGIやTIのようなdiag_suppressも使用しますが、構文は異なります。一部の警告番号は同じですが、私は別の警告番号を付けました:#pragma diag_suppress=Pe1444,Pe1215
  • ペレ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プラグマは関数のoutsideでなければなりませんでした。

血みどろの詳細を隠す

ほとんどのコンパイラでは、C99で導入された_Pragmaを使用して、マクロの背後にあるロジックを隠すことができます。非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

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

簡単な方法:ヘドリー

コードをきれいに保ちながら、このようなことを移植可能にする方法の仕組みを理解したので、私のプロジェクトの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を更新するときにこの回答を更新することはおそらくありません)。そして、動作することが知られていないコンパイラーでは、マクロは何も前処理されないため、コードはどのコンパイラーでも動作し続けます。もちろん、HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATEDは、Hedleyが知っている唯一の警告ではなく、すべてのHedleyが実行できる警告を無効にしているわけではありませんが、うまくいけばアイデアが得られます。

2
nemequ