コンパイラの警告を常に有効にする必要があるのはなぜですか?


302

CおよびC ++プログラムをコンパイルするとき、「コンパイラの警告を常に有効にする」必要があるとよく耳にします。なぜこれが必要なのですか?それ、どうやったら出来るの?

「警告をエラーとして扱う」べきだとも時々聞いています。したほうがいい?それ、どうやったら出来るの?

回答:


341

警告を有効にする理由

CおよびC ++コンパイラーは、以下のようなプログラマーの一般的な間違いをデフォルトで報告することで悪名高く有名です

  • 変数の初期化を忘れている
  • return関数から値を忘れる
  • 内の引数printfscanfファミリがフォーマット文字列と一致しません
  • 関数が事前に宣言されずに使用されている(Cのみ)

これらは通常はデフォルトでは検出および報告できません。この機能は、コンパイラオプションを介して明示的に要求する必要があります。

警告を有効にする方法は?

これはコンパイラによって異なります。

マイクロソフトCおよびC ++コンパイラは、スイッチが好きな理解/W1/W2/W3/W4/Wall。少なくとも使用してください/W3/W4また/Wall、システムヘッダーファイルに対して誤った警告を発する可能性がありますが、プロジェクトがこれらのオプションのいずれかで正常にコンパイルされる場合は、それに従ってください。これらのオプションは相互に排他的です。

他のほとんどのコンパイラは次のようなオプションを理解し-Wall-Wpedanticそして-Wextra-Wallが不可欠であり、残りはすべて推奨されます(その名前にもかかわらず、すべて-Wall警告ではなく、最も重要な警告のみを有効にすることに注意してください)。これらのオプションは、個別にまたはすべて一緒に使用できます。

IDEには、ユーザーインターフェイスからこれらを有効にする方法がある場合があります。

警告をエラーとして扱うのはなぜですか?彼らはただの警告です!

コンパイラの警告は、コードに潜在的に深刻な問題があることを示します。上記の問題はほとんどの場合致命的です。他の人はそうかもしれないしそうでないかもしれませんが、それが誤った警報であることが判明したとしてもコンパイルを失敗させたいです。各警告を調査し、根本原因を見つけて修正します。誤警報の場合は、回避してください。つまり、別の言語機能または構成を使用して、警告がトリガーされないようにします。これが非常に難しいことが判明した場合は、その特定の警告をケースバイケースで無効にします。

すべてが誤報であっても、警告をそのまま警告として残したくない場合。警告の総数が7未満の非常に小規模なプロジェクトでは問題ないかもしれません。それ以上の場合、古い警告の洪水で新しい警告が失われるのは簡単です。それを許してはいけない。すべてのプロジェクトをきれいにコンパイルするだけです。

これはプログラム開発に適用されることに注意してください。プロジェクトをソース形式で世界にリリースする場合-Werrorは、リリースされたビルドスクリプトで同等の機能を提供しないことをお勧めします。人々は、異なるバージョンのコンパイラーを使用して、または異なるコンパイラーを使用してプロジェクトをビルドしようとする可能性があり、異なる警告セットが有効になっている可能性があります。あなたは彼らのビルドを成功させたいかもしれません。警告メッセージを見る人があなたにバグ報告やパッチを送ることができるように、警告を有効にしておくことはそれでも良い考えです。

警告をエラーとして扱う方法は?

これも、コンパイラスイッチで行われます。/WXマイクロソフト用であり、他のほとんどが使用します-Werror。どちらの場合も、警告が生成されるとコンパイルは失敗します。


107
私はこのQ&Aを投稿しました。警告を有効にするように人々に告げるのにうんざりしてうんざりしているからです。今、私は彼らをここに向けることができます(または、私が特に邪悪な気分になっている場合は、彼らの質問をだましとして閉じます)。この回答を改善するか、独自に追加してください。
n。「代名詞」m。

16
また、使用することができ打ち鳴らすの-Weverything
PMG

9
追加する唯一の修飾子は、一部の警告がアプリケーションに役立たない場合があることです。(コンパイラーが構造体の要素の間に2バイトのパディングを追加したという警告を見ました。アプリケーションはプロトタイピング用でしたので、少しのメモリの浪費は気になりませんでした。)すべての警告をエラーとして扱い、次の場合にのみ警告を無効にします。その警告が役に立たない理由を知っています。
カイルA

20
デフォルトのビルド手順に従う人にとって警告をエラーとして扱うことの欠点は、コンパイラが新しい警告を追加するときにコードが腐敗することです。自分のコードをダウンロードして将来ビルドしようとするユーザーは、コンパイラーが古すぎて、余分な括弧やコンパイラーが気にしていないものについて警告を発するため、できない場合があります。エラーが発生したユーザーは、コードやビルドシステムの責任を負わず、警告をエラーとして扱うことをオフにして実際にプロジェクトをビルドする方法を知りません。
interfect

15
@interfectはい、これは私に数回起こりました。大したことはありません。あなたが構築することを選択した場合はメンテナンスされていない、それはでテストされなかったコンパイラを使用してソフトウェアの一部を、よく、あなたはより良いいくつかのmainenanceを自分でやるために準備します。
n。「代名詞」m。

94

Cは、有名なことですが、HLLのようにかなり低レベルの言語です。C ++は、Cよりもかなり高水準の言語のように見えるかもしれませんが、それでも多くの特徴を共有しています。そして、それらの特徴の1つは、言語がプログラマー、特にプログラマーが何をしているかを知っているプログラマーのために設計されたことです。

[この回答の残りの部分では、Cに焦点を当てます。私が言うことのほとんどはC ++にも当てはまりますが、それほど強くはないかもしれません。Bjarne Stroustrupが有名に言ったように、「Cは足で自分を撃つことを簡単にします; C ++はそれを難し​​くしますが、それを行うと脚全体を吹き飛ばします。」]

あなたが何をしているのかを知っているなら-あなたは何をしているのか本当に知っています-時々あなたは「ルールを破る」必要があるかもしれません。しかし、ほとんどの場合、私たちのほとんどは、善意のルールが私たち全員をトラブルから守ることに同意し、それらのルールを常に破ることだけが望まれるのは悪い考えです。

しかし、CおよびC ++では、「悪い考え」であるが、正式には「ルールに反する」ことではない、驚くほど多くのことができます。時々それらは悪い考えです(しかし、他の場合は防御可能かもしれません)。時々それらは事実上常に悪い考えです。しかし、伝統は常にこれらのことについて警告することではありませんでした-繰り返しになりますが、プログラマは彼らが何をしているのかを知っているという仮定です、彼らは正当な理由なしにこれらのことをしていません不要な警告の。

しかしもちろん、すべてのプログラマが実際に何をしているのかを知っているわけではありません。そして、特に、すべてのCプログラマーは(経験の豊富さを問わず)、初心者のCプログラマーになる段階を経ます。また、経験豊富なCプログラマでさえ、不注意でミスをする可能性があります。

最後に、経験から、プログラマは間違いを犯すだけでなく、これらの間違いが実際に深刻な結果をもたらす可能性があることがわかっています。間違いを犯し、コンパイラーが警告せず、何らかの理由でプログラムがすぐにクラッシュしないか、明らかにそれが原因で何かがおかしい場合、間違いはそこに潜み、何年もの間、それが原因になるまで隠れてしまうことがあります本当に大きな問題。

結局のところ、ほとんどの場合、警告は良い考えであることがわかります。経験豊富なプログラマーでさえ(実際には、「特に経験豊富なプログラマーが習得したもの」です)、警告は害を及ぼすよりも効果がある傾向があることを学びました。意図的に何か間違ったことをして警告が煩わしいたびに、少なくとも10回は誤って何か間違ったことをしたことがあり、警告はさらなるトラブルからあなたを救いました。また、ほとんどの警告は、本当に「間違った」ことを実行したいときに、無効にしたり、回避したりすることができます。

(例えばA「間違い」の古典的な例は、テストされif(a = b)た時間のほとんどは、これは間違いである、これらの日はそれについて警告するので、ほとんどのコンパイラ- 。いくつかのも、デフォルトではしかし、あなたがいる場合。本当に割り当ての両方に望んでいたbaとテストその結果、と入力して警告を無効にできますif((a = b))。)

2番目の質問は、警告をエラーとして処理するようコンパイラーに要求する理由は何ですか?それは人間の性質、特に「ああ、それは単なる警告であり、それほど重要ではないので、後で整理します」という非常に簡単な反応によるものだと思います。しかし、あなたが先延ばし屋であるなら(そして私はあなたのことを知りませんが、私はひどい先延ばし屋です)、基本的にいつまでも必要なクリーンアップを延期することは簡単です-そして、あなたが警告を無視する癖になったら、それはあなたが無視しているすべてのメッセージの真ん中に、気づかれずにそこに座っている重要な警告メッセージを見逃しやすくなります。

したがって、コンパイラに警告をエラーとして処理するように依頼することは、この人間の可能性を回避するために自分で試すことができる小さなトリックです。

個人的には、警告をエラーとして扱うことにこだわることはありません。(実際、正直に言えば、「パーソナル」プログラミングでそのオプションを事実上有効にしたことはないと私は言うことができます。)しかし、職場でそのオプションを有効にしていることは確かです。スタイルガイド(書いた)その使用を義務付けています。Cのエラーが無責任に振る舞うとして警告を処理しないショップは、一般に受け入れられている業界のベストプラクティスに準拠していないと私は言います-ほとんどのプロのプログラマーは言うと思います-。


9
「彼らが何をしていたかを知っているプログラマー」-LOL; 「本当のスコットランド人ではない」という誤解があります。私がこれを見たとしたら、それは
間違いです。)

3
@Dancrumb LOLバックatcha。真のスコットランド人の誤謬を理解しているとは確信が持てませんが、私はそれが好きなので、これは私にとって良い練習になるでしょう。ここでのアプリケーションは次のようになると思います。「Cプログラマーはを書かif(a = b)ないので、警告する必要はありません。」(そして、誰かがこの特定のエラーの結果としてリリースされた10個の製品で10個の重大なバグのリストを作成します。)「さて、経験豊富な Cプログラマーがこれを書くことはありません...」
Steve Summit

3
@SteveSummitしかし、実際に経験豊富なCプログラマが書くことif (returnCodeFromFoo = foo(bar))とキャプチャに、それを意味し、一つの場所にコードをテスト(想定のみの目的はfoo、副作用を持つことです!)という事実本当に経験豊富なプログラマはこのことを知っている可能性はありません良いコーディングスタイルは
要点を外してい

5
問題は、ほとんどの経験豊富なプログラマーがすべてではないにしてもほとんどの警告を有効にすることです。彼らがのようなものを使用したい場合if (returnCodeFromFoo = foo(bar))は、コメントを入れて警告をオフにします(メンテナンスプログラマーが4年後にそれを見ると、彼/彼女はコードが意図的であることに気付くでしょう。それで私は働いた(Microsoft C ++の土地では)/ Wallを組み合わせて警告をエラーとして扱うのが良い方法だと主張した人とは、そうではありません(多くの抑制コメントを入れたくない限り)
Flydog57

3
日常的にコードを書かない人として、しかし私それを行うとき、それはベアメタルである傾向があります(多くの場合、自分のデザインのボード上にあります)。内部レジスターに値を詰め込むとき(DMA記述子の場所の例です)、ポインターへの変換に関する警告は、警告をクリアするためのキャストを行うことを意味します。それはエラーではありませんが、誰か他の人(または私自身!)が数か月以内にそのコードを見つけた場合、混乱を招く可能性があります。さらに、CADツールの出力にも「警告なし」ルールを適用します。
Peter Smith、

39

警告は、一部の最も熟練したC ++開発者がアプリケーションに焼き込むことができる最良のアドバイスで構成されています。それらは保持する価値があります。

チューリング完全言語であるC ++には、コンパイラーが自分が何をしているか知っていると単純に信頼しなければならない場合がたくさんあります。しかし、おそらくあなたが書いたものを書くつもりがなかったとコンパイラが認識できる多くの場合があります。古典的な例は、引数に一致しないprintf()コード、またはprintfに渡されるstd :: stringsです(これは私には起こりません)。これらの場合、記述したコードはエラーではありません。これは、コンパイラーが動作するための有効な解釈を持つ有効なC ++式です。しかし、コンパイラーには、最新のコンパイラーが検出しやすい何かを見落としているという強い直感があります。これらは警告です。それらはコンパイラーにとって明白であり、C ++のすべての厳密なルールを自由に使用しているため、見落としている可能性があります。

警告をオフにする、または無視することは、あなたより熟練した人からの無料のアドバイスを無視することを選択するようなものです。フベリスでのレッスンは、太陽に近づきすぎて翼が溶けるか、メモリ破壊エラーが発生したときに終了します。二人の間は、いつの日か空から落ちます!

「警告をエラーとして扱う」は、この哲学の極端なバージョンです。ここでの考え方は、コンパイラーが与えるすべての警告を解決することです。無料のアドバイスを少しずつ聞いて、それに基づいて行動します。これが開発に適したモデルであるかどうかは、チームと、作業している製品の種類によって異なります。それは僧侶が持つかもしれない禁欲的なアプローチです。一部の人にとっては、それはうまくいきます。他の人にとっては、そうではありません。

私のアプリケーションの多くでは、警告をエラーとして扱いません。これらの特定のアプリケーションは、さまざまな時代のいくつかのコンパイラを備えたいくつかのプラットフォームでコンパイルする必要があるため、これを行います。別のプラットフォームで警告にならなければ、一方の側で警告を修正することが実際には不可能であることが時々あります。だから私たちは単に注意しています。私たちは警告を尊重しますが、警告を後退させません。


11
C ++が完全にチューリングしていることは、それと関係があります。多くの言語は完全に
Goodbye SE

3
@KamiKazeすべての言語には慣用的なミスがあり(たとえば、Javaが一貫性のないequals/ を書くのを止めることはできませんhashCode)、それは実装品質の問題であり、どれが報告されていますか。
Caleth

2
@KamiKazeチューリング完全性ビットは、コードが計画どおりに機能しないことをコンパイラーが証明できない場合があることを示すために使用されます。コンパイラはすべての「間違った」コードをエラーにすることができないため、これは重要です。エラーは、言語設計者が常に「間違っている」と確信している動作に対してのみ予約できます。(通常、一貫性のないパスにつながるため)。
Cort Ammon

2
これは、「すべての警告はエラーである」という課題も示しています。警告は、設計上、より便宜的であり、誤ったコードでより頻繁にトリガーする代わりに、潜在的に正しいコードでトリガーされます。エラーとしての警告は、言語の全機能を実行できないことを意味します。
Cort Ammon

2
ただし、一般に、プログラマーは「安全な」以上のことを行う言語を求めています。私たちが言ったと思っていることを実行する言語が必要です。したがって、コンピュータに実行してほしい実際のクラスはセマンティッククラスであるため、警告は引き続き重要です。コンパイラーは「不正」または「安全でない」と定義することでそれを選択できますが、最終的にはプログラマーがプログラムに実行させたい動作のスーパークラスがまだあります。警告は、そのスーパークラスを絞り込むのに役立ちます。
Cort Ammon、

19

警告を処理することでコードが改善されるだけでなく、プログラマーも改善されます。警告は、今日あなたにはほとんど見えないかもしれないことについて教えてくれますが、ある日、その悪い習慣が戻ってあなたの頭をかむでしょう。

正しいタイプを使用し、その値を返し、その戻り値を評価してください。時間をかけて、「これはこのコンテキストで本当に正しいタイプですか?」「これを返す必要がありますか?」そして大物; 「このコードは今後10年間移植可能ですか?」

そもそも、警告のないコードを書く習慣を身につけましょう。


17

他の答えは素晴らしく、私は彼らが言ったことを繰り返したくありません。

適切に触れられていない「なぜ警告を有効にするのか」のもう1つの側面は、コードの保守に非常に役立つことです。大きなサイズのプログラムを書くと、一度に全部を頭の中に留めておくことは不可能になります。あなたは通常、あなたが積極的に書いて考えている関数や3つ、そしておそらくあなたが参照できるファイルや3つを画面上に持っていますが、プログラムの大部分はどこかにバックグラウンドで存在し、それを信頼する必要があります働き続けます。

警告を出し、可能な限り元気で顔に警告を表示することで、何か変更を加えて、見えないものに問題が生じた場合に警告することができます。

たとえば、clangの警告を見てください-Wswitch-enum。列挙型でスイッチを使用し、考えられる列挙型の値の1つを見逃した場合、警告がトリガーされます。これは、ありそうもない間違いであると考えるかもしれません。おそらく、switchステートメントを記述したときに、おそらく列挙値のリストを見ました。IDEでスイッチオプションを生成し、人為的エラーの余地を残さない場合もあります。

この警告は、6か月後に列挙型に別のエントリを追加したときに実際に発生します。繰り返しになりますが、問題のコードについて考えているのであれば、おそらく大丈夫でしょう。しかし、この列挙型が複数の異なる目的で使用され、追加オプションが必要なものの1つである場合、6か月間触れていないファイルのスイッチを更新するのを忘れることは非常に簡単です。

警告は、自動テストケースと同じように考えることができます。警告は、コードが適切であるかどうかを確認し、最初に記述したときに必要なことを実行するのに役立ちますが、それを確実にするためにさらに役立ちます。あなたがそれに向かっている間、あなたは必要なことをし続けます。違いは、テストケースはコードの要件に対して非常に狭い範囲で機能し、コードを記述しなければならないことですが、警告はほとんどすべてのコードの賢明な標準に幅広く対応し、コンパイラを作成するボフィンによって非常に寛大に提供されます。


9
彼らがメンテナンスを支援するもう1つの方法は、他の誰かのコードを見ていて、副作用が意図的なものであったかどうかを判断できない場合です。警告をオンにすると、少なくとも問題を認識していたことがわかります。
ロビンベネット

あるいは、私の場合、数千の値を持つ列挙に対して3000以上の行切り替えステートメントを含むファイルを組み込みシステムからインポートします。「フォールスルー」警告(gotoを使用することで回避)は、いくつかの「処理されない」バグを覆い隠しました...組み込みコンパイラはそれらのいずれも出力しませんでしたが、それでもバグは重要でした。
MOZ

15

修正されていない警告は、遅かれ早かれ、コードのエラーにつながります


たとえば、セグメンテーションフォールトのデバッグでは、プログラマーがフォールトの根本(原因)をトレースする必要があります。これは通常、最終的にセグメンテーションフォールトを引き起こした行よりもコードの前の場所にあります。

原因はコンパイラが無視した警告を発行した行であり、セグメンテーション違反の原因となった行は最終的にエラーをスローした行です。

警告を修正すると、問題が修正されます。

上記のデモンストレーションです。次のコードを検討してください。

#include <stdio.h>

int main(void) {
  char* str = "Hello world!";
  int idx;

  // Colossal amount of code here, irrelevant to 'idx'

  printf("%c\n", str[idx]);

  return 0;
}

「Wextra」フラグをGCCに渡してコンパイルすると、次のようになります。

main.c: In function 'main':
main.c:9:21: warning: 'idx' is used uninitialized in this function [-Wuninitialized]
    9 |   printf("%c\n", str[idx]);
      |                     ^

いずれにして、コードを無視して実行することができます。そして、IPエピキュラスの教授がよく言っていたように、「大規模な」セグメンテーション違反を目にします。

セグメンテーション違反

これを実際のシナリオでデバッグするには、セグメンテーション違反の原因となっている行から開始して、原因の根本となるものを追跡しようとします。その膨大な量の内部istr内部で何が起こったかを検索する必要があります。あそこのコードの...

ある日まで、彼らidxは初期化されていない状態で使用されていることに気づき、ガベージ値を持っています。これにより、文字列(ウェイ)のインデックスが範囲外になり、セグメンテーション違反が発生します。

警告を無視していなければ、すぐにバグを見つけたでしょう。


4
タイトルに:必ずしもそうではありません。たとえば、実際に括弧を必要としない数式で括弧を使用することを提案する警告は、決してエラーを引き起こさない問題ではないことを示しています。特定のプログラミング言語での演算子の優先順位は変わりません。ずっと。
マルクファンレーウェン

4
@MarcvanLeeuwen たとえば、演算子の優先順位を覚えていないプログラマが式を少し修正した場合など、引用するインスタンスがエラーになる可能性があります。この警告は、「ある時点では不明瞭になる可能性があるため、かっこを追加してより明確にする」と説明しています。ただし、元の投稿のタイトルが常に正しいとは限らないことに同意する必要があります。
Hubert Jasieniecki

^何かがエラーになる可能性があります。完全に括弧で囲まれたコードと同じように、部分的に括弧で囲まれたコードにバグを導入するのは簡単です。
ジムBalter

...さておき、私が持っていたような質問の最初の反応デバッガのために「ああ、それはからsegfaultedにstr[idx]いません「さて、あるstridx定義された`?
ジャスティン・タイム-復活モニカ

2
セグメンテーション違反が発生しても幸運です。運が悪い場合は、偶然にidxテストで期待した値になり(期待値が0の場合はそれほどあり得ないことではありませんが)、実際に展開時に印刷してはならない機密データを実際に指すことがあります。
celtschk

14

警告をエラーとして扱うことは、自己規律の単なる手段です。あなたはその光沢のある新機能をテストするためにプログラムをコンパイルしていましたが、ずさんな部分を修正するまではできません。追加情報Werrorはありません。優先順位を非常に明確に設定するだけです。

既存のコードの問題を修正するまで、新しいコードを追加しないでください

重要なのはツールではなく、マインドセットです。コンパイラ診断出力はツールです。MISRA(組み込みC用)は別のツールです。どちらを使用するかは問題ではありませんが、おそらくコンパイラの警告は最も簡単に入手できるツールであり(設定するフラグは1つだけです)、S / N比は非常に高くなります。したがって、使用しない理由はありません

間違いのないツールはありません。と書いた場合const float pi = 3.14;、ほとんどのツールでは、πを精度の悪い値で定義したことが通知されないため、今後問題が発生する可能性があります。ほとんどのツールはif(tmp < 42)、変数に意味のない名前を付けてマジックナンバーを使用することが大きなプロジェクトで災いをもたらす方法であることが一般的に知られている場合でも、に眉をひそめません。作成する「クイックテスト」コードは単なるテストであることを理解する必要があります。他のタスクに進む前に、そのコードの欠点を確認しながらコードを取得する必要があります。そのコードをそのままにしておくと、2か月後に新しい機能を追加した場合のデバッグは非常に難しくなります。

いったん正しい考え方に入ると、を使用しても意味がありませんWerror。警告として警告を設定すると、開始しようとしたデバッグセッションを実行しても意味があるのか​​、それとも中止して最初に警告を修正するのかを、情報に基づいて決定できます。


3
良くも悪くも、clippyRust のリンティングツールは定数「3.14」について実際に警告します。これは実際にはdocsの例です。ただし、名前から推測できるように、clippy積極的に役立つことに誇りを持っています。
EMK

1
@emkこの例をありがとう、多分私は決して「絶対に」決して言わないような方法で私の答えを言い換える必要があります。不正確なπ値をチェックすることは不可能だと言ったわけではありません。単に警告を取り除くだけでは、適切なコード品質が保証されるわけではありません。
Dmitry Grigoryev

エラーとして警告されることの1つは、自動化されたビルドが失敗するため、何かが間違っていることを警告することです。自動化も爆発が3 ... 2 ... 1である(毛羽立ち自動化を可能に.. :)構築する
MOZ

8

レガシー組み込みCコードで作業する人として、コンパイラ警告を有効にすると、修正を提案するときに調査すべき多くの弱点と領域が示されます。gccで利用することは-Wall-Wextraさらに-Wshadow重要になっています。私はすべてのハザードに行くつもりはありませんが、コードの問題を示すのに役立つポップアップされたものをいくつか挙げます。

残された変数

これは、問題になる可能性のある渡された変数のすべてを利用していない可能性がある未完成の作業と領域を簡単に指摘できます。これをトリガーする可能性のある単純な関数を見てみましょう。

int foo(int a, int b)
{
   int c = 0;

   if (a > 0)
   {
        return a;
   }
   return 0;
}

-Wallまたは-Wextraなしでこれをコンパイルしても問題はありません。-壁はそれcが使用されることはありませんがあなたに教えてくれます:

foo.c:関数 'foo':

foo.c:9:20:警告:未使用の変数 'c​​' [-Wunused-variable]

-Wextraは、パラメーターbが何もしないことも通知します。

foo.c:関数 'foo':

foo.c:9:20:警告:未使用の変数 'c​​' [-Wunused-variable]

foo.c:7:20:警告:未使用のパラメーター 'b' [-Wunused-parameter] int foo(int a、int b)

グローバル変数のシャドウイング

これは少しハードで、-Wshadow使用されるまで表示されませんでした。上記の例を変更して追加するだけですが、ローカルと同じ名前のグローバルがたまたまあり、両方を使用しようとすると多くの混乱を引き起こします。

int c = 7;

int foo(int a, int b)
{
   int c = a + b;
   return c;
}

-Wshadowがオンになっていると、この問題を簡単に見つけることができます。

foo.c:11:9:警告: 'c'の宣言はグローバル宣言をシャドウイングします[-Wshadow]

foo.c:1:5:注:シャドウされた宣言はここにあります

フォーマット文字列

これはgccで追加のフラグを必要としませんが、過去の問題の原因となっています。データを印刷しようとする単純な関数ですが、フォーマットエラーは次のようになります。

void foo(const char * str)
{
    printf("str = %d\n", str);
}

これは、フォーマットフラグが間違っているので文字列を出力しません。gccは、これがおそらく望んだものではないことを喜んで教えてくれます。

foo.c:関数 'foo':

foo.c:10:12:警告:フォーマット '%d'はタイプ 'int'の引数が必要ですが、引数2のタイプは 'const char *'です[-Wformat =]


これらは、コンパイラーが再確認できる多くのことの3つにすぎません。他の人が指摘した初期化されていない変数を使用するような他の多くがあります。


7
組み込みの世界では、私が最も心配する警告は「possible loss of precision」と「comparison between signed and unsigned」の警告です。これらを無視する "プログラマ"の数を把握するのは難しいと思います(実際、なぜそれがエラーではないのかよく
わかり

3
後者の場合、@ Mawg、それがエラーではない主な理由は、結果sizeofが符号なしであることですが、デフォルトの整数型は符号付きです。sizeof結果の型は、size_t一般に整数を「として使用されることが意図されているが、典型的には、例えば、配向または配列/コンテナ要素数、として、文字サイズに関連する何のために使用されint、さもなければ必要とされない限り」。このようにint、コンテナを反復処理するために何人の人が使用するように教えられているかを考えると(と比較intしてsize_t)、エラーにすると、ほぼすべてが壊れます。; P
ジャスティンタイム-モニカを復活

6

これはCに対する具体的な回答であり、これがCにとって他の何よりもはるかに重要である理由です。

#include <stdio.h>
int main()
{
   FILE *fp = "some string";
}

このコードは警告付きでコンパイルされます。地球上のほぼすべての他の言語(アセンブリ言語を除く)のエラーとは、Cの警告です。Cの警告はほとんどの場合、偽のエラーです。警告は、抑制されるのではなく、修正されるべきです。

ではgcc、これをとして行いますgcc -Wall -Werror

これは、一部のMSの非セキュアAPI警告に関する高い保証の理由でもありました。Cをプログラミングするほとんどの人は警告をエラーとして扱うための難しい方法を学んでおり、これは同じ種類のものではなく、移植できない修正が必要であるように見えました。


5

コンパイラの警告はあなたの友人です(強調するために大文字で叫んではいけません)。

私はレガシーのFortran-77システムで作業しています。コンパイラーは私に貴重なことを教えてくれます:使用されていない変数またはサブルーチンの引数がある場合、値が変数に設定される前にローカル変数を使用して、サブルーチンの呼び出しで引数のデータ型が一致しません。これらはほとんど常にエラーです。

長い投稿の回避:コードが正常にコンパイルされると、97%が機能します。私が一緒に作業しているもう1人の人は、すべての警告をオフにしてコンパイルし、デバッガーで数時間または数日費やしてから、助けを求めます。私は警告をオンにして彼のコードをコンパイルし、修正すべきことを彼に伝えます。


5

コンパイラは多くの場合、コードの問題点を通知できるため、常にコンパイラ警告を有効にする必要があります。これを行う-Wall -Wextraには、コンパイラに渡します。

通常、警告はコードに問題があることを示しているため、警告はエラーとして扱う必要があります。ただし、多くの場合、これらのエラーは無視するのが非常に簡単です。したがって、それらをエラーとして扱うとビルドが失敗するため、エラーを無視できません。警告をエラーとして扱う-Werrorには、コンパイラに渡します。


4

C ++のコンパイラ警告は、いくつかの理由で非常に役立ちます。

1-操作の最終結果に影響を与える可能性のあるミスを犯した可能性のある場所を示すことができます。たとえば、変数を初期化しなかった場合、または「==」の代わりに「=」を配置した場合(例のみがあります)

2-コードがc ++の標準に準拠していない場所を示すこともできます。コードが実際の標準に準拠している場合、たとえば、コードを他のプレートフォームに簡単に移動できるので便利です。

一般に、警告は、アルゴリズムの結果に影響を与えたり、ユーザーがプログラムを使用するときにエラーを防止したりできるコードの間違いを示すのに非常に役立ちます。


4

警告を無視すると、ずさんなコードが残されて、将来誰かに問題が発生するだけでなく、重要なコンパイルメッセージが気づかなくなります。コンパイラーの出力が多いほど、だれも気づかないか、気になりません。きれいなほうがいい。また、自分が何をしているかを知っていることも意味します。警告は非常に専門的ではなく、不注意で、危険です。


4

私はかつて、電子試験装置を製造する大企業(フォーチュン50)で働いていました。

私のグループの中核製品はMFCプログラムで、長年にわたって文字通り何百もの警告を生成するようになりました。ほとんどすべてのケースで無視されました。

これは、バグが発生したときの悪夢です。

そのポジションの後、私は幸運にも新しいスタートアップの最初の開発者として雇われることができました。

コンパイラの警告レベルをかなりうるさく設定して、すべてのビルドに「警告なし」ポリシーを推奨しました。

私たちの習慣は、#pragma警告を使用することでした-念のため、開発者が本当に問題のないコードに対してpush / disable / popを実行し、デバッグレベルのログステートメントを使用しました。

この実践は私たちにとってはうまくいきました。


1
出向。 #pragma warning警告を抑制するだけでなく、何かが意図的で偶発的ではないことを他のプログラマーに迅速に伝えるという二重の目的を果たし、何かが壊れたが潜在的に問題のある領域をすばやく見つけるための検索タグとして機能しますが、エラー/警告を修正することはできません修理する。
ジャスティン時間-

あなたは正しいジャスティンです、それがまさに私が#pragma警告を表示した方法です
ジムインテキサス

3

警告は、発生を待機しているエラーです。したがって、コンパイラの警告を有効にし、コードを整理して警告を削除する必要があります。


3

警告をエラーとして処理することで問題が1つだけあります。他のソース(micro $ ** tライブラリ、オープンソースプロジェクトなど)からのコードを使用している場合、それらは正しく機能せず、コードをコンパイルすると大量に生成されます警告の。

私は常に警告やエラーを生成しないようにコードを記述し、無関係なノイズを生成せずにコンパイルされるまでコードをクリーンアップします。私が扱う必要のあるゴミは私を驚かせ、大きなプロジェクトを構築し、一連の警告がコンパイルで処理されたファイルのみを通知するはずであるところを通過しなければならないことに驚かされます。

ソフトウェアの実際の生涯コストは、最初にそれを作成することからではなく、メンテナンスに起因することがわかっているため、コードも文書化しますが、それは別の話です...


ノックしないでください。クライアントへのコンパイラの警告を大声で読むことができる人々のためのコンサルティング業務にはかなりのお金があります。
MOZ

警告を生成する他のソースからのコードは、作者がだらしないことを必ずしも意味しません。また、異なる警告セットを生成する別のコンパイラでコードをコンパイルしたことを意味する場合もあります。コードは、あるコンパイラでは警告なしでコンパイルでき、別のコンパイラでは警告を生成できます。あるいは、警告オプションの異なるセットにすぎないかもしれません。例えば彼らは使用し-Wall、あなたは使用します-Wall -Wextra
celtschk

2

一部の警告は、コードまたはUBのセマンティックエラーの可能性を意味する場合があります。例:;if()、未使用の変数、ローカルによってマスクされたグローバル変数、または符号付きと符号なしの比較。多くの警告は、コンパイラーの静的コードアナライザーまたはコンパイル時に検出可能なISO規格の違反に関連しており、「診断が必要」です。これらの発生は特定のケースでは合法である場合がありますが、ほとんどの場合、設計上の問題の結果です。

gccなどの一部のコンパイラには、「警告をエラーとして」モードをアクティブにするコマンドラインオプションがあります。これは、残酷な場合でも、初心者のプログラマーを教育するための優れたツールです。


1

C ++コンパイラが、明らかに未定義の動作引き起こすコンパイルコードを受け入れるという事実は、コンパイラの大きな欠陥です。彼らがこれを修正しない理由は、そうすることはおそらくいくつかの使用可能なビルドを壊してしまうからです。

警告のほとんどは、ビルドの完了を妨げる致命的なエラーでなければなりません。エラーを表示してビルドを実行するというデフォルトは間違っています。エラーをオーバーライドして警告をエラーとして扱い、いくつかの警告を残すようにしないと、プログラムがクラッシュし、ランダムな処理が行われる可能性があります。


皮肉なことに、未定義の動作の多くは実際には警告を引き起こしませんが、静かにコンパイルして厄介な小さな時限爆弾にうまく動作します。; P
ジャスティンタイム-モニカを

1
問題は、規格がエラーメッセージを要求する場合、問題が発生するすべてのケースでそのエラーメッセージを発行する必要があることですが、問題が発生しない場合は決して発行しません。しかし、未定義の動作などの場合、それを決定することは不可能かもしれません。たとえば、次のコードを考えてみましょう。int i; if (fun1()) i=2; if (fun2()) i=3; char s="abcde"[i];このコードの展示がある場合にのみ、両方の場合の動作は未定義fun1()fun2()返すことができfalse、同じ機能の実行に。どちらが本当かそうでないかもしれませんが、コンパイラはどのように伝えるのですか?
celtschk

-2

一部のコンパイラーは、以下を含むいくつかの一般的なプログラミングの誤りを報告するのが得意ではないため、コンパイラーの警告を必ず有効にする必要があります。

->変数の初期化が忘れられる->関数から値が返される-失敗する-> printfおよびscanfファミリの単純な引数がフォーマット文字列と一致しない事前に宣言されていない関数が使用されるが、cでのみ発生する

したがって、これらの関数は検出および報告できるため、通常はデフォルトではありません。そのため、この機能はコンパイラオプションを介して明示的に要求する必要があります。


-32

安心してください。必要はありません。必要はありません。-Wallと-Werrorは、コードリファクタリングマニアックによって設計されましたユーザー側でコンパイラを更新した後、既存のビルドを壊さないようにするために、コンパイラ開発者によって開発されました。機能は何もありませんが、ビルドを中断するかどうかの決定に関するすべてです。

それを使用するかどうかは完全にあなたの好み次第です。間違いを修正するのに役立つので、私はいつもそれを使用しています。


19
必須ではありませんが、使用することを強くお勧めします
Spikatrix

18
-Wall and -Werror was designed by code-refactoring maniacs for themselves.[引用が必要]
YSC

22
自分と矛盾しているようです。「[間違い]を修正するのに役立つので、常にそれを使用する」なら、新しいプログラマーに教えて、最初からどこでもできるようにする価値はありませんか?この質問は、and なしでコンパイルできるかどうかを尋ねているとは思いません。-Wallそして-Werror、それが良いアイデアかどうかを尋ねているだけです。あなたの最後の文から、それはあなたがそう言っているように聞こえます。
scohe001

12
自分で作成したものではないコードを保守する経験が増えたら、この回答に再度アクセスしてください。
するThorbjörnRavnアンデルセン

これは役に立ちません。OPの質問には4つの疑問符があります。この返信はいくつ返答しますか?
アンデルス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.