Objective-C開発用のClang警告フラグ


86

CおよびObjective-Cプログラマーとして、私はコンパイラ警告フラグに少し偏執的です。
私は通常、使用しているコンパイラの警告フラグの完全なリストを見つけて、それをオンにしない本当に正当な理由がない限り、それらのほとんどをオンにします。

私は個人的に、これにより実際にコーディングスキルが向上し、コードの移植性が向上し、いくつかの問題を防ぐことができると考えています。

私の意見では、あなたが経験豊富なプログラマーであっても、毎日の良い学習ツールでもあります。

この質問の主観的な部分については、このトピックについて他の開発者(主にC、Objective-C、C ++)を聞くことに興味があります。
あなたは実際に、物足りなさの警告などのようなものに関心がありますか?はい、またはいいえの場合、なぜですか?

Objective-Cについては、最近、GCCではなく、LLVMツールチェーン(Clangを使用)に完全に切り替えました。

私の製品コードでは、通常、この警告フラグを設定します(明示的に、それらの一部が-Wallでカバーされている場合でも):

  • -壁
  • -Wbad-function-cast
  • -Wcast-align
  • -W変換
  • -ステートメント後の宣言
  • -Wdeprecated-implementations
  • -ウェクストラ
  • -Wfloat-equal
  • -Wformat = 2
  • -Wformat-nonliteral
  • -Wfour-char-constants
  • -Wimplicit-atomic-properties
  • -ミッシングブレース
  • -ミッシング宣言
  • -欠落フィールド初期化子
  • -欠落フォーマット属性
  • -ミッシングノーリターン
  • -ミッシングプロトタイプ
  • -ネストされた外部
  • -改行-eof
  • -Wold-style-definition
  • -Woverlength-strings
  • -かっこ
  • -ポインターポインター
  • -冗長宣言
  • -戻り型
  • -Wsequence-point
  • -Wshadow
  • -Wshorten-64-to-32
  • -Wsign-compare
  • -署名変換
  • -Wstrict-prototypes
  • -Wstrict-selector-match
  • -Wswitch
  • -Wswitch-default
  • -Wswitch-enum
  • -Wundeclared-selector
  • -初期化されていない
  • -不明なプラグマ
  • -到達不能コード
  • -未使用機能
  • -未使用ラベル
  • -未使用パラメーター
  • -未使用値
  • -未使用変数
  • -Wwrite-strings

他の開発者がこのことについて何と言っているのかを聞きたいです。

たとえば、Clang(Objective-C)の特定のフラグを見逃したと思いますか?
または、特定のフラグが役に立たないと思いますか(またはまったく望んでいません)、なぜですか?

編集

質問を明確にするために、-Wallいくつかの基本的な警告のみを提供していることに注意してください。
それらは実際にはもっと多くの警告フラグであり、でカバーされていない-Wallため、質問であり、私が提供するリストです。


9
これはおそらくツールの使用法に関する質問なので、おそらくStack Overflowにとどまるべきだと言いたくなりますが、コミュニティがどのように変化するかがわかります。
アダムリア

コメントをありがとう:)ある意味では、私はあなたに同意します、そして、それが私が最初にStackOverflowにこれを投稿した理由です(また、私はここに普通のユーザーではないので、恥ずべきです)たくさんの意見、賛成票などを得ました...しかし、単一の答えではありません...そして人々がそれを動かすように提案したように...さて、見てみましょう:)
Macmade

さて、私たちはあなたに良い答えを与えることができると思います。幸運を。:)
アダムリア

Cとgccの場合、-Wwrite-strings非常によく似た言語のコンパイラになりますが、厳密にはCではありません。そのため、このオプションのみを使用しません。あなたが指定したもの以外に、私は完全に合理的な初期化子のために使用-pedantic -Wstrict-overflow=5 -Winline -Wundef -Wcast-qual -Wlogical-op -Wstrict-aliasing=2-Wno-missing-braces -Wno-missing-field-initializersますstruct whatever obj = {0};。また-Wconversion、有用な警告よりも多くの「スパム」を与えることがわかります:)
pmg

回答:


158

コンテキストについては、私はGoogleで働いているClang開発者です。Googleでは、Clangの診断を(本質的に)すべてのC ++開発者に公開し、Clangの警告もエラーとして扱います。Clangの開発者であり、Clangの診断の大規模なユーザーの1つでもあるので、これらのフラグとその使用方法に光を当てるつもりです。ここで説明するものはすべてClangに一般的に適用可能であり、C、C ++、またはObjective-Cに固有のものではないことに注意してください。

TL; DRバージョン:開発中の新しいコードを少なくとも使用-Wall-Werrorてください。私たち(コンパイラ開発者)は、正当な理由で警告をここに追加します:彼らはバグを見つけます。バグをキャッチする警告を見つけた場合は、同様にオンにします。-Wextraここでたくさんの良い候補者を探してみてください。それらのいずれかがあなたにとって有益であるためにうるさすぎる場合は、バグを報告してください。「明らかな」バグを含むコードを作成しても、コンパイラがそれについて警告しなかった場合は、バグを提出してください。

長いバージョンになりました。警告フラグのグループ化に関する最初の背景。Clangには(そしてGCCには限られた範囲で)多くの警告の「グループ化」があります。この議論に関連するもの:

  • デフォルトで:これらの警告は、明示的に無効にしない限り常にオンです。
  • -Wall:これらは、開発者がその価値と低い誤検知率の両方に高い信頼を持っているという警告です。
  • -Wextra:これらは、価値があり健全であると考えられている警告です(つまり、バグではありません)が、偽陽性率が高いか、一般的な哲学的反対がある場合があります。
  • -Weverything:これは、 Clangのすべての警告を文字通り有効にする非常識なグループです。コードでこれを使用しないでください。それは厳密にClang開発者か、どんな警告が存在するかを調査することを意図しています

上記の2つの主要な基準があり、Clangで警告がどこに送られるかをガイドし、これらが本当に意味することを明確にしましょう。1つ目は、特定の警告発生の潜在的な です。これは、警告が発生 し、コードの問題を正しく識別する場合に、ユーザー(開発者)に期待される利点です。

2番目の基準は、誤検知レポートのアイデアです。これらは、コードに対して警告が発せられる状況ですが、引用されている潜在的な問題は、プログラムのコンテキストまたはその他の制約のために実際には発生しません。警告されたコードは実際には正しく動作しています。これらは、そのコードパターンで警告が発動されることを意図していなかった場合、特に悪いです。代わりに、警告の実装に欠陥があるため、警告が発生します。

Clangの警告の場合、はスタイル、好み、コーディング規約ではなく、正確さの観点から求められます。これにより、使用可能な警告のセットが制限{}され、ifステートメントの本文でsが使用されていない場合は常に警告などの頻繁に要求される警告が除外されます。Clangは偽陽性にも非常に不寛容です。他のほとんどのコンパイラとは異なり、コンストラクトの正確なスペル、余分な「()」、キャスト、プリプロセッサマクロの有無など、誤検知を排除するために、信じられないほど多様な情報ソースを使用します!

次に、Clangからの実際の警告の例をいくつか見て、それらがどのように分類されるかを見てみましょう。まず、デフォルトの警告:

% nl x.cc
     1  class C { const int x; };

% clang -fsyntax-only x.cc
x.cc:1:7: warning: class 'C' does not declare any constructor to initialize its non-modifiable members
class C { const int x; };
      ^
x.cc:1:21: note: const member 'x' will never be initialized
class C { const int x; };
                    ^
1 warning generated.

ここでは、この警告を取得するのにフラグは必要ありません。理由は、これはコードが決して正しいとは限らず、警告値が高くなり、警告はClangがこのバケットに入ることを証明できるコードでのみ発生し、誤検知率がゼロになることです。

% nl x2.cc
     1  int f(int x_) {
     2    int x = x;
     3    return x;
     4  }

% clang -fsyntax-only -Wall x2.cc
x2.cc:2:11: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
  int x = x;
      ~   ^
1 warning generated.

Clangでは、-Wallこの警告にフラグが必要です。その理由は、初期化されていない値を意図的に生成することを警告しているコードパターンを(善悪を問わず)使用している重要なコードがそこにあるためです。哲学的には、これには何の意味もありませんが、他の多くの人は意見が異なり、この意見の違いの現実が-Wall旗の下で警告を駆り立てるもの です。依然として非常に高い価値と非常に低い 検知率を持っていますが、一部のコードベースでは、それは非スターターです。

% nl x3.cc
     1  void g(int x);
     2  void f(int arr[], unsigned int size) {
     3    for (int i = 0; i < size; ++i)
     4      g(arr[i]);
     5  }

% clang -fsyntax-only -Wextra x3.cc
x3.cc:3:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
  for (int i = 0; i < size; ++i)
                  ~ ^ ~~~~
1 warning generated.

この警告には-Wextraフラグが必要です。その理由は、 比較の符号の不一致が非常に一般的である非常に大きなコードベースがあるためです。この警告にはいくつかのバグがありますが、ユーザーが書いたときにコードがバグになる可能性は平均してかなり低いです。その結果、非常に高い偽陽性率が得られます。プログラムのバグが原因奇妙なプロモーションルールにがある場合しかし、それはこの警告をすることが多い、非常に微妙な バグがとき、それはフラグが比較的高い持っている価値を。結果として、Clangはそれを提供し、フラグの下で公開します。

通常、警告は-Wextraフラグの外側では長く続きません。Clangは、通常の使用とテストが行​​われない警告を実装しないように非常に努力しています。によってオンにされる追加の警告-Weverythingは、通常、アクティブな開発中またはアクティブなバグがある警告です。それらは修正され、適切なフラグの下に配置されるか、削除する必要があります。

これらがClangでどのように機能するかを理解できたので、元の質問に戻りましょう。開発のためにどの警告をオンにする必要がありますか?残念なことに、答えはそれによって異なります。次の質問を考慮して、状況に最も適した警告を判断してください。

  • すべてのコードを制御できますか、それとも外部のコードですか?
  • あなたの目標は何ですか?バグをキャッチする、またはより良いコードを書く?
  • あなたの偽陽性耐性は何ですか?警告を沈黙させるために、定期的に追加のコードを作成してもよろしいですか?

何よりもまず、コードを制御しない場合は、追加の警告を表示しないでください。オフにする準備をしてください。世界には多くの不正なコードがあり、すべてを修正できるとは限りません。それは大丈夫です。制御するコードに努力を集中させる方法を見つけるために働きます

次に、警告から何を望むかを考えます。これは人によって異なります。Clangは、重大なバグ、またはバグ率が非常に高いことを示す長い歴史的な先例があるコードパターンに関するオプションなしで警告しようとします。-WallClang開発者がC ++コードで観察した最も一般的な間違いを見つけることを目的とした、より積極的な一連の警告を取得できるようになります。しかし、これらの両方で、 偽陽性率は非常に低いままでなければなりません。

最後に、ターンごとに* 誤検出 *を完全に黙らせたい場合は、に進み-Wextraます。多くの実際のバグをキャッチしているが、愚かな、または無意味な誤検知がある警告に気付いた場合は、バグを提出してください。私たちは常にに存在するバグ検出ロジックのより多くをもたらすための方法を見つけるために取り組んでいる-Wextra-Wall我々は偽陽性を避けることができる場所を。

多くの人は、これらのオプションはどれもそれらにぴったりではないことに気付くでしょう。Googleでは、-Wall既存のコードの多くが警告に違反しているため、いくつかの警告をオフにしました。また-Wall、特に価値が高いため、によって有効にされていなくても、いくつかの警告を明示的にオンにしました。走行距離はさまざまですが、同様の方法で変わる可能性があります。多くの場合、すべてではなく、いくつかの重要な警告を有効にする方がはるかに優れています -Wextra

私は励ます皆をオンにする-Wall任意の非レガシーコードのために。新しいコードの場合、ここでの警告はほとんど常に価値があり、実際にコード開発の経験を改善します。逆に、を超えてフラグを有効にしないことを皆に勧めます -Wextra。Clangの警告が-Wextra 含まれていませんが、それがあなたにとってまったく価値があることがわかった場合は、バグを報告てください-Wextra。警告の一部のサブセットを明示的に有効にするかどうか-Wextraは、コード、コーディングスタイル、およびリストを維持することが、で明らかになったすべてを修正するよりも簡単かどうかに大きく依存します-Wextra

(両方含ま警告のOPのリスト-Wallとの-Wextra唯一の次の警告がされている)ではないものを二つのグループによってカバーされ(またはデフォルトでオンになって)。最初のグループは、明示的な警告フラグへの過度の依存が悪い理由を強調しています。これらはどれもClangに実装されていません!GCCとの互換性のためにのみ、コマンドラインで使用できます。

  • -Wbad-function-cast
  • -Wdeclaration-after-statement
  • -Wmissing-format-attribute
  • -Wmissing-noreturn
  • -Wnested-externs
  • -Wnewline-eof
  • -Wold-style-definition
  • -Wredundant-decls
  • -Wsequence-point
  • -Wstrict-prototypes
  • -Wswitch-default

元のリストの次の不要な警告のバケットは、そのリストの他の警告と重複しています。

  • -Wformat-nonliteral -のサブセット -Wformat=2
  • -Wshorten-64-to-32 -のサブセット -Wconversion
  • -Wsign-conversion -のサブセット -Wconversion

また、より明確に異なる警告の選択もあります。これらは、バグのあるコードやバグのないコードではなく、言語の方言の変形を扱います。を除き-Wwrite-strings、これらはすべてClangが提供する言語拡張機能に関する警告です。Clangがその使用について警告するかどうかは、拡張機能の普及度に依存します。ClangはGCCの互換性を目的としているため、多くの場合、広く使用されている暗黙の言語拡張機能によってそれを容易にします。-Wwrite-stringsOPでコメントされているように、プログラムのセマンティクスを実際に変更するGCCの互換性フラグです。私はこのフラグを深く後悔していますが、現在のレガシーのためにサポートする必要があります。

  • -Wfour-char-constants
  • -Wpointer-arith
  • -Wwrite-strings

潜在的に興味深い警告を実際に有効にしている残りのオプションは次のとおりです。

  • -Wcast-align
  • -Wconversion
  • -Wfloat-equal
  • -Wformat=2
  • -Wimplicit-atomic-properties
  • -Wmissing-declarations
  • -Wmissing-prototypes
  • -Woverlength-strings
  • -Wshadow
  • -Wstrict-selector-match
  • -Wundeclared-selector
  • -Wunreachable-code

これらが含まれていない、-Wallまたは-Wextra常に明確ではない理由。これらの多くについては、実際にはGCC警告(、など)に基づいている-Wconversionため -Wshadow、ClangはGCCの動作を模倣しようとします。これらの一部を徐々に、よりきめ細かく有用な警告に分解しています。これらは、トップレベルの警告グループの1つになる可能性が高くなります。それは1回の警告で、選択する、と述べ-Wconversionているので、それは可能性が予見可能な将来のために、独自の「トップレベル」カテゴリ残ることを幅広いです。GCCは持っているが、他のいくつかの警告は低い値持っている高い偽陽性率は、同様の無man's-土地に追いやられます。

これらが大きなバケットの1つに含まれない他の理由には、単純なバグ、非常に重大な誤検知の問題、および開発中の警告が含まれます。識別できるバグのファイリングバグを調べます。最終的にはすべて適切な大きなバケットフラグに移行するか、Clangから削除する必要があります。

これにより、Clangの警告状況が明らかになり、使用または会社の使用のために一連の警告を選択しようとする人々に何らかの洞察が得られることを願っています。


8
抜群の答え!どうもありがとう。何度か読み直す必要がありますが、すぐにコメントを付けて戻ってきます。再度、感謝します!
Macmade

1
@Chandler Carruth:すばらしい答えです!しかし、何か変更があった場合、更新してもらえますか?私はあなたの最後のリストであなたの警告をすべて使用していますが、おそらくいくつかはすでにウェクストラに移されていますか?
-gartenriese

これは素晴らしい投稿です。しかし、新しい警告を見つけることは、フラグの非常に優れた使用法であることがわかったので、この種の調査に役立つことを認めているにもかかわらず、「すべて」のグループに対して非常に否定的な態度をとっていることに失望しています。
カイルストランド

@Chandler Carruth:「絶対に正しいことはない」コードに関する警告の背後にある理論的根拠に同意します。決して持っていないだけだということを-Wnoオフにすることwarn_no_constructor_for_refconst :それはPITA Boost.ConceptCheckと同様に使用できるようになりgithub.com/boostorg/concept_check/blob/...
mloskot

2

私はClangを使用しませんが、私の意見も気にしないでください。また、最大警告レベル(これが-Wallの意味だと思います)で警告をエラーとして扱い(これが-Werrorの意味だと思います)、あまり意味のないいくつかの警告のみを無効にします。実際、C#コンパイラによって特定の非常に有用な警告が発行されず、それらを確認するには特別なコード分析ツールを実行する必要があるという事実に非常に悩まされています。私は警告が好きです。それは、コードの小さな間違いやバグを見つけるのに役立つからです。私はそれらがとても好きなので、正しいとわかっているコードの一部に対して警告が発行された場合、警告を無効にするのではなく、警告が発行されないように、とにかくそのコードをリファクタリングします。さらに悪いことに、それを表示させて無視してください。警告は素晴らしいと思いますが、


1
答えてくれてありがとう。残念ながら、-Wall基本的な警告のみを提供します。既存の警告フラグの多くはでカバーされていない-Wallため、私の質問のリストです。
Macmade

0

私は通常、新しいプロジェクトのXcodeのデフォルト設定を使用します。有益なものと迷惑なもののバランスがとれています。警告およびその他のコンパイラオプションの特定のリストは、個人的な好みまたはプロジェクトの要件に大きく基づいているため、リストを調べて特定の警告に賛成または反対することはあまり価値がないと思います。それがあなたのために働くなら、素晴らしい。コンパイラーが検出できるはずのエラーを見つけた場合、今後その支援が必要な場合は、コンパイラーオプションを探して警告し、有効にします。

多くのプログラマーが提唱していることの1つは、警告がある場合にビルドが正常に完了しないようにするために、「警告をエラーとして扱う」(-Werror)オプションをオンにすることです。


答えてくれてありがとう!に同意し-Werrorます。実際、Clangを使用しているため、これらの警告はすべてプラグマ(#pragma clang diagnostic)を使用して設定し、致命的なエラーに設定されているため、これは次と同じ-Werrorです。)
Macmade

0

人々が警告を気にする最も良い証拠は、警告が存在し、広く使用されているという事実だと思います。コンパイル時に検出されるエラーが多いほど良いという意見を強く持っています。これが広く信じられていなかった場合、コンパイラーまたはインタープリターがより多くの余裕を与えるので、誰もが弱い動的に型付けされた言語を使用するでしょう。それどころか、スクリプト言語でもstrictフラグの使用が一般的です。静的な強く型付けされた言語では、人々は-Wall -Werror頻繁に使用するだけでなく、多くの場合、警告が非常に貴重であるため、さらに多くを必要とするため、Coverityのような警告を提供することのみを目的とする静的分析ツールの代価を払っています。

それは中傷者がいないという意味ではありません。多くの開発者は、警告を長期的には自分たちのために働いているのではなく、短期間で働いていると見なし、根本的な問題を修正しようとはしません。したがって、昨日出会ったこのスニペットのような素敵なコードが表示されます。

node = node; // Shut up compiler warning

ご回答有難うございます。問題は、多くの場合、人々がなし-Werrorで作業し、実際にコンパイラによって発行された警告を無視することです。または、そうする場合、彼らは通常に固執し-Wallます。私の質問で提供するフラグのほとんどはでカバーされておらず-Wall、個人的にはそれらも不可欠だと思います。だから私はただの妄想ですか?; )
Macmade

0

一般的に、私は-Wallにもっと傾いており、-Werrorも含めることを間違いなく信じています。モジュールに予期される警告が表示されることはありません。最終的に別の警告が表示され、見逃します。そして、それが実際に問題になるものです。

また、新しいプロジェクトと古いプロジェクトのどちらに「-Wall -Werror」を追加するかによって異なります。それが新しいなら、それを手に入れて完璧を求めましょう。古いやや小さいプロジェクトでこれをやっただけで、2、3日かけて警告を削除しました。コードは今ではきれいになったと思います。

つまり、試してみてください。

ランディ


1
あなただけに関係している場合-Wall-Werror、私はあなたが質問を再読み込みする必要がありますね。多くの警告フラグはでカバーされていません-Wall。とにかく答えてくれてありがとう。
Macmade
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.