未使用の変数に関する警告を無音にする方法を教えてください。


237

クロスプラットフォームアプリケーションがあり、一部の関数では、関数に渡されるすべての値が使用されていません。したがって、未使用の変数があるというGCCからの警告が表示されます。

警告をコーディングする最良の方法は何ですか?

関数の周りの#ifdef?

#ifdef _MSC_VER
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal qrLeft, qreal qrTop, qreal qrWidth, qreal qrHeight)
#else
void ProcessOps::sendToExternalApp(QString sAppName, QString sImagePath, qreal /*qrLeft*/, qreal /*qrTop*/, qreal /*qrWidth*/, qreal /*qrHeight*/)
#endif
{

これは醜いですが、コンパイラーが好む方法のようです。

または、関数の最後で変数にゼロを割り当てますか?(コンパイラの警告を消すためにプログラムフロー内の何かを変更しているため、これは嫌いです)。

正しい方法はありますか?


7
昨年11月に同様の質問をしたことに気づきました。これが見慣れた理由です!;)stackoverflow.com/questions/308277/...
アレックスB

9
両方のコンパイラでコメントアウトしないのはなぜですか?引数が1つで使用されていない場合、おそらくもう1つで使用されません...
Roger Lipscombe

12
QtにはQ_UNUSEDこのためのマクロがあることを知っておく必要があります。ドキュメントで確認してください。
エヴァン・テラン

1
Cソリューションは、あまりにもC ++での罰金に動作します:stackoverflow.com/a/3599170/1904815
JonnyJD

-Wno-unused-parameterは、コンパイラー固有のビルドフラグを使用できる場合のオプションにもなる可能性があります
コードアボミネーター

回答:


327

」式に入れることができます(void)var;コンパイラーがそれが使用されている(何もしません)。これはコンパイラ間で移植可能です。

例えば

void foo(int param1, int param2)
{
    (void)param2;
    bar(param1);
}

または、

#define UNUSED(expr) do { (void)(expr); } while (0)
...

void foo(int param1, int param2)
{
    UNUSED(param2);
    bar(param1);
}

22
+1-それでも、変数があるのになぜそれを使用しないのかを文書化します。
トビアスラングナー

18
これはQ_UNUSED、原則としてどのように実装されるかです。
Dmitry Volosnykh 2012年

11
@Cameronの場合、C ++ではパラメーター名を省略できます。テンプレート化されている場合は、Cでは使用されないため、cast-to-voidトリックは必要ありません。
Alex B

13
ジャスト#define UNUSED(expr) (void)(expr)(DO-しばらくなし)あまりにも動作するはずです。
JonnyJD 2014

7
可変テンプレートの場合はどうすればいいのでしょうか。でtemplate<typename... Args> void f(const Args&... args)書けない(void)args;(void)args...;、どちらも構文エラーのためです。
panzi 2014年

101

GCCとClangでは、__attribute__((unused))プリプロセッサディレクティブを使用して目標を達成できます。
例えば:

int foo (__attribute__((unused)) int bar) {
   return 0;
}

1
これは、コールバック関数の最良のソリューションです。
Sonic Atom

1
:また、打ち鳴らすでサポートされているclang.llvm.org/docs/...
アレクサンダー


39

現在の解決策が最適です。使用しない場合は、パラメータ名をコメント化してください。これはすべてのコンパイラに当てはまるため、GCC専用にプリプロセッサを使用する必要はありません。


7
この答えを強調するために、#ifdefは必要ありません。未使用のパラメーター名をコメント化してください。
quamrana 2009

4
パラメータがコールバックの一部であり、コメント化するとコンパイルが失敗する場合があります(そのため、なぜg++警告されているのかわかりません)。このような場合、何をお勧めしますか?
Drew Noakes 2013年

1
未使用のパラメーターを含むインライン仮想メソッド/ * commented * /を想像してください。ほとんどのIDEの自動補完中に、インターフェイスのクライアントにはパラメーター名が表示されません。この場合、UNUSED()ソリューションの方が便利ですが、それほどクリーンではありません。
cbuchart 2014

私はシンプルな方が良いと思います。コメントアウトは非常に明確です
fievel 2018年

26

C ++ 17アップデート

C ++ 17では、[dcl.attr.unused]でカバーされる属性[[maybe_unused]]取得します

attribute-token maybe_unusedは、名前またはエンティティーが意図的に未使用であることを示します。これは各属性リストに最大1回出現し、attribute-argument-clauseは存在しません。...

例:

 [[maybe_unused]] void f([[maybe_unused]] bool thing1,
                        [[maybe_unused]] bool thing2) {
  [[maybe_unused]] bool b = thing1 && thing2;
    assert(b);
 }

実装では、NDEBUGが定義されているかどうかにかかわらず、bが未使用であることを警告するべきではありません。—例を終了]

次の例の場合:

int foo ( int bar) {
    bool unused_bool ;
    return 0;
}

clangとgccはどちらも、-Wall -Wextraを使用して、barunused_boolの両方に対して診断を生成しますライブでご覧ください)。

[[maybe_unused]]を追加すると、診断が停止します

int foo ([[maybe_unused]] int bar) {
    [[maybe_unused]] bool unused_bool ;
    return 0;
}

ライブでご覧ください

C ++ 17より前

C ++ 11では、未使用の変数をキャプチャUNUSEDしたラムダ式(Ben Deaneを介して)を使用して、マクロの代替形式を形成できます。

#define UNUSED(x) [&x]{}()

次の例を考えると、ラムダ式の即時呼び出しは最適化する必要があります。

int foo (int bar) {
    UNUSED(bar) ;
    return 0;
}

godboltで、呼び出しが最適化されていることがわかります。

foo(int):
xorl    %eax, %eax
ret

5
それで、あなたはC ++ 11に言及し、それからなんとかマクロを提示するのですか?痛い!たぶん関数を使うほうがきれいでしょうか?template <class T> inline void NOTUSED( T const & result ) { static_cast<void>(result); }関数でラムダを使用することもできます。
Alexis Wilke

godboltは素晴らしいリソースです
矢野

5
[&x]{}()警告は実際には消音されませんが、呼び出し元の関数からラムダに警告が渡されます。コンパイラがこれを警告として識別するまでには時間がかかりますが、clang-tidyはキャプチャリスト内の未使用の変数について既に不平を言っています。
nVxx 2018

25

さらにすっきりとした方法は、変数名をコメント化することです。

int main(int /* argc */, char const** /* argv */) {
  return 0;
}

8
これは、doxygenを使用していて、パラメーターを文書化する場合には適していません。
Alexis Wilke、2014

18
@AlexisWilke:それはIMOのdoxygenのバグと見なされます
6502

3
int main(int YOUR_PROJECT_UNUSED(argc)、...)を使用して、#ifdef DOXYGENに基づいて条件付きでYOUR_PROJECT_UNUSED(argname)を#defineして、doxygenが名前を認識し、実際のコンパイラが認識しないようにすることができます。すばらしいとは言えませんが、うまくいきます。
マブラハム

このようなネストされたコメントが多数含まれているコードブロックをコメントアウトするのは非常に苦痛です。(コンパイラーはすべてについて不平を言います)。
ジェフマクリントック

@JeffMcClintockは、単一行コメントを使用します。ほとんどのまともなエディターは垂直ブロック編集をサポートしています(例えばVimでは[Ctrl] + [V])。それ以外の場合は、#if 0 / #endifブロックコメントを使用します。
ルスラン

24

同僚が私にここでこの素敵な小さなマクロを指摘しまし

簡単にするために、以下のマクロを含めます。

#ifdef UNUSED
#elif defined(__GNUC__) 
# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) 
#elif defined(__LCLINT__) 
# define UNUSED(x) /*@unused@*/ x 
#else 
# define UNUSED(x) x 
#endif

void dcc_mon_siginfo_handler(int UNUSED(whatsig))

12
"nice" "macro" "c ++"-ピック2
Jeff McClintock

23

デフォルトではこれらの警告にフラグを立てません。この警告は-Wunused-parameter、コンパイラに渡すことによって明示的に、または渡すことによって暗黙的に-Wall -Wextra(またはフラグの他の組み合わせ)オンになっているはずです。

未使用のパラメーターの警告は-Wno-unused-parameter、コンパイラーに渡すことで簡単に抑制できますが、この無効化フラグは、コンパイラーのコマンドラインでこの警告の有効化フラグの後にある必要があります。


2
これは質問に対する最良の回答ではないかもしれませんが(質問は警告を無効にする方法ではなく、回避する方法であったため)、この回答はGoogle(私のように)から来た人々が検索した( "方法この警告を無効にします」)。+1を差し上げます。回答ありがとうございます。
mozzbozz 2014

13

1つまたは複数のパラメーターを未使用として宣言するためのマクロなしの移植可能な方法:

template <typename... Args> inline void unused(Args&&...) {}

int main(int argc, char* argv[])
{
    unused(argc, argv);
    return 0;
}

非常に良いですが、これにはC ++ 11(もちろんそれ以降)が必要です。
Paul R

警告を取り除くためだけに(テンプレートを使用して)コンパイル時間を犠牲にしたくないので、私はこの回答に反対票を投じました。
Konrad Kleine

@KonradKleine:これにより、コンパイル時間がどれだけ消費される可能性がありますか?私のコンピューターでテストすると、これらの未使用の呼び出しを10分の1秒で実行できます。
Daniel

@DanielMcLauryこれは私の推測であり、私は実験を行っていません。
Konrad Kleine

8

ほとんどの場合、プリプロセッサディレクティブの使用は悪と見なされます。理想的には害虫のようにそれらを避けたいです。コンパイラにコードを理解させるのは簡単で、他のプログラマがコードを理解できるようにするのははるかに難しいことに注意してください。あちこちでこのような数十のケースがあると、後で自分で読んだり、今すぐ他の人が読んだりすることが非常に難しくなります。

1つの方法は、パラメーターをある種の引数クラスにまとめることです。次に、変数のサブセットのみを使用するか(実際に0を割り当てるのと同じ)、プラットフォームごとにその引数クラスの異なる特殊化を使用できます。ただし、これは価値がないかもしれません。それが適合するかどうかを分析する必要があります。

不可能なテンプレートを読むことができる場合は、「Exceptional C ++」の本に高度なヒントが見つかるかもしれません。あなたのコードを読む人がその本で教えられているクレイジーなものを取り巻くスキルセットを手に入れることができれば、あなたも簡単に読むことができる美しいコードを手に入れるでしょう。コンパイラーは、(前処理によってすべてを非表示にするのではなく)あなたが何をしているかをよく知っています。


5
「プリプロセッサディレクティブの使用は、ほとんどの場合悪と見なされます。」本当に?誰によって?
Graeme Perrow、

12
スコープ、適切にデバッグできること、またはその正気に関心がある人。
ビル

2
@ Graeme、4行しか表示されない場合は無害に見えますが、周りに広がると頭痛の原因になります。#ifdefは基本的に、コンパイラーが1つしか認識しないソースコードの複数のバージョンを置くことができます。Billが言及しているように、デバッグも難しくなります。私は、さまざまな本やブログでプリプロセッサディレクティブの悪さについて読んだり、自分で経験したことがあります。もちろん、すべてが相対的です。場合によっては、プリプロセッサディレクティブが意味をなさない場合があるため、プリプロセッサディレクティブが単に意味をなす場合もあります。私の要点は、可能な限り回避することだけです。
Ben Dadsetan

1
使い過ぎは悪いですが、私は#define UNUSED(expr) (void)(expr)適切だと思います。
JonnyJD 2014

7

まず、警告はヘッダーファイルではなくソースファイルの変数定義によって生成されます。APIドキュメントを生成するためにdoxygenのようなものを使用している可能性があるため、ヘッダーは元の状態を保つことができます。

私はあなたがソースファイルに完全に異なる実装を持っていると仮定します。これらの場合、問題のあるパラメーターをコメント化するか、パラメーターを書き込むことができます。

例:

func(int a, int b)
{
    b;
    foo(a);
}

これは不可解に見えるかもしれないので、UNUSEDのようなマクロを定義しました。MFCの方法は次のとおりです。

#ifdef _DEBUG
#define UNUSED(x)
#else
#define UNUSED(x) x
#endif

このように、デバッグビルドでまだ警告が表示されていると、役立つ場合があります。


4

パラメータ名を常にコメントアウトするのは安全ではありませんか?そうでない場合は、次のようなことができます

#ifdef _MSC_VER
# define P_(n) n
#else
# define P_(n)
#endif

void ProcessOps::sendToExternalApp(
    QString sAppName, QString sImagePath,
    qreal P_(qrLeft), qreal P_(qrTop), qreal P_(qrWidth), qreal P_(qrHeight))

それは少し醜いです。


4
C ++ではパラメーター名が必須ではない-Cでは必須であるという事実は、警告を防ぐための標準的で簡単な方法を提供するためだけです。
AProgrammer 2009

1
@ハッカー、それがそうであると言ったことはありません。私はCとC ++の違いを指摘する傾向があります。特に、それらが一般的なサブセットであると思われる領域にある場合は...混合コードベースで作業しているので、単なる習慣です。
AProgrammer 2009

4

私は(void)param2警告を沈黙させる方法の代わりにこれを見ました:

void foo(int param1, int param2)
{
    std::ignore = param2;
    bar(param1);
}

これはC ++ 11で追加されたようです


コンパイル後に無視されずに何かをしているようです。
GyuHyeon Choi

3

を使用して UNREFERENCED_PARAMETER(p)できます。私はそれがWindowsシステムのWinNT.hで定義されており、gccでも簡単に定義できることを知っています(まだ持っていない場合)。

UNREFERENCED PARAMETER(p) と定義されている

#define UNREFERENCED_PARAMETER(P)          (P)

WinNT.hで。



1

を使用__unusedして、変数が使用されない可能性があることをコンパイラに通知できます。

- (void)myMethod:(__unused NSObject *)theObject    
{
    // there will be no warning about `theObject`, because you wrote `__unused`

    __unused int theInt = 0;
    // there will be no warning, but you are still able to use `theInt` in the future
}

2
どのコンパイラー?__unusedは標準のC ++ではないため、要点を言えば、どちらもあなたが投稿したものではありません...それはObjective-Cです。したがって、この回答は特定のコンパイラにのみ有用であり、コードを移植不可能にします。実際、ユーザーコードは__、実装用に予約されているで始まる識別子を使用することを意図していないため、実際には無効です。
underscore_d

1

C ++ 11では、これは私が使用しているソリューションです。

template<typename... Ts> inline void Unreferenced(Ts&&...) {}

int Foo(int bar) 
{
    Unreferenced(bar);
    return 0;
}

int Foo2(int bar1, int bar2) 
{
    Unreferenced(bar1, bar2);
    return 0;
}

移植性があり(少なくとも最新のmsvc、clang、およびgccでは)、最適化が有効になっているときに余分なコードを生成しないことが確認されています。最適化なしで、追加の関数呼び出しが実行され、パラメーターへの参照がスタックにコピーされますが、関連するマクロはありません。

追加のコードに問題がある場合は、代わりに次の宣言を使用できます。

(decltype(Unreferenced(bar1, bar2)))0;

しかし、その時点で、マクロは読みやすくなります。

#define UNREFERENCED(...) { (decltype(Unreferenced(__VA_ARGS__)))0; }

1

これはうまく機能しますが、C ++ 11が必要です

template <typename ...Args>
void unused(Args&& ...args)
{
  (void)(sizeof...(args));
}

1
これについてはC ++ 14が必要で、C ++ 11では機能しませんか?何も見えません。また、ALLCAPSマクロ以外のものには使用しないことをお勧めします。マクロを醜く望ましくないものにするためですが、実際には、これstatic_castよりも良いことを除いて、何も悪いことはありません。
underscore_d

0

提示された回答のほとんどがローカルの未使用変数に対してのみ機能し、未使用の静的グローバル変数に対してコンパイルエラーが発生することがわかりました。

未使用の静的グローバル変数の警告を抑制するために必要な別のマクロ。

template <typename T>
const T* UNUSED_VARIABLE(const T& dummy) { 
    return &dummy;
}
#define UNUSED_GLOBAL_VARIABLE(x) namespace {\
    const auto dummy = UNUSED_VARIABLE(x);\
}

static int a = 0;
UNUSED_GLOBAL_VARIABLE(a);

int main ()
{
    int b = 3;
    UNUSED_VARIABLE(b);
    return 0;
}

匿名名前空間の非静的グローバル変数については警告が報告されないため、これは機能します。

C ++ 11が必要ですが

 g++  -Wall -O3  -std=c++11 test.cpp

0

笑!私は、カオスによって破壊されたすべての異端をこの問題よりも明らかにするSOに別の質問があるとは思いません!

C ++ 17へのすべての敬意をもって、C ++コアガイドラインに明確なガイドラインがあります。AFAIR、2009年に戻って、このオプションは今日と同様に利用可能でした。そして誰かがそれをDoxygenのバグと見なすと言ったら、Doxygenにバグがあります


-14

警告であなたの問題はわかりません。コンパイラーxyが(正しい)警告を発行するが、これらの変数はプラットフォームzに必要であることをメソッド/関数ヘッダーに文書化します。

警告は正しいので、オフにする必要はありません。プログラムを無効にすることはありませんが、理由があることを文書化する必要があります。


20
問題は、そのような警告が数百または数千ある場合、役立つ警告を見逃す可能性があることです。(2度私は数万の警告を回避し、ほとんどを排除し、重大なエラーをほのめかしたときに本当に役立つものをいくつか見つける状況にありました。)可能であれば、警告なしでコンパイルすることは、最高の警告レベルで常に良いことです。
sbi 2009

4
昨年取り組んだプロジェクトで、私は最高の警告レベルをオンにして、最大10,000件の警告を受け取りました。ほんの数ダースだけが本当に役に立ちました。それらの中には12の本当に厄介なバグが隠されていましたが、実際にいくつかの深刻なバグが見えるようになるまでコードベースをきれいにするのに数人週間かかりました。警告レベルが常に上がっていて、コードベースが警告なしに保たれていれば、それらのエラーがコードに侵入することは決してなかったでしょう。
sbi 2009

1
申し訳ありませんが、プロジェクトの後半で静的コード分析を(コンパイラだけでも使用可能なツールを使用して)行うのは、プログラム全体をプログラミングするようなものです。完了したら、コンパイルを押して、エラーがないことを願ってください。
トビアスラングナー

2
@リチャード:私は何千ものソースファイルを含むプロジェクトに取り組みました。あちこちに小さな警告があり、十分に文書化されたものであっても、すぐに追加されます。ビルド中に数百または数千ではなく数十の警告しか表示されない場合でも、個別に調べて新しいものかドキュメント化されたものかを確認するのは時間がかかりすぎて、結局のところ、行われます。そのため:警告なしで、可能な限り最高の警告レベルでコンパイルします。発生するすべての警告はすぐに通知され、確認され、修正されるか抑制されます。
sbi 2009

2
@sbi:コンパイラの最も高い警告レベルでの調整は、静的コード分析の一種です。静的コード分析とは、コードを実行して情報を差し引くことなく、コードを読み取ることです。これは、コンパイラが警告のルールをチェックするときにまさに行うことです。
Tobias Langner、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.