レガシープロジェクトで警告に対処する方法


9

膨大な数の警告を生成するC ++プロジェクトに取り組んでいます。ほとんどの警告は、コードの作成後に表示されました。

  • 当初、プロジェクトはVisual C ++ 8を使用し、間もなく9に切り替えましたが、生成された警告にほとんど違いがありません。警告は修正されるか沈黙されたので、そのとき警告はありませんでした。
  • 次に、64ビットターゲットが追加されました。これは、主に型の不適切な使用(unsignedvsなどsize_t)のために、大量の警告を生成しました。コードが目的に沿って機能した後は、誰もそれらを修正するために悩んだり時間をかけたりすることはありませんでした。
  • 次に、GCCを使用する他のプラットフォームのサポート(4.5および4.6、最初は4.4)が追加されました。GCCはよりうるさいので、より多くの警告を生成しました。再び、誰もそれらを修正するために悩んだり、時間をかけたりしませんでした。これは、GCCが4.5まで特定のコードの警告を沈黙させるプラグマを持っていなかったという事実によってさらに複雑になり、ドキュメントによると、それはまだ必要なものではありません。
  • その間、いくつかの非推奨の警告がポップアップしました。

これで、何千もの警告を生成するプロジェクトができました。また.cpp、さまざまなコンパイラーによってファイルが数回コンパイルされ、ヘッダーの警告が何度も出力されるため、どのくらいの数の場所であるかさえわかりません。

そのようなものをクリーンアップするためのベストプラクティスはありますか?それともそれを扱った少なくともいくつかの肯定的な経験ですか?

回答:


4

レガシーコードには触れないでください。今のところ警告を抑制する方法を見つけてください。コードに一見無害な変更を加えると、コードにバグが発生する可能性があります。これは、すでにテスト済みで、バグが比較的少ないと思います。

現在コードベースにあるすべての警告を抑制することにより、白紙の状態を装うことができます。コードに導入された新しい警告は削除する必要があり、古いコードが書き直された場合、新しい実装は警告を抑制すべきではありません。

ここでのあなたの目標は:

  1. 信号/ノイズ比を減らします。開発者がビルド時に何千もの通知を確認しても、masterブランチには2004通知があり、ブランチには2006があることに気づかないでしょう。

  2. これ以上のバグは導入しないでください。前述の無害な変更を行うことにより、予期しないバグが発生する可能性があります。これは、何千もの警告がある場合に特に関係があります。エラー率が信じられないほど低い場合でも、失敗する可能性は何千もあります。

  3. レガシーコードが新しいコードの基準を下げないようにしてください。クラスの警告が抑制されたからといって、新しいクラスでも同じことができるわけではありません。最終的には、注意を払って、レガシーコードがコードベースから削除され、警告のない新しいコードに置き換えられます。


1
+1「コードに一見無害な変更を加えると、コードにバグが発生する可能性があります...」-レガシーコードでは、自動テストが行​​われることはほとんどありません。これらのバグは見つかりません。
mattnz 2013

@mattnz:実際、小さな自動テストはレガシーコードと非レガシーコードの両方に広がっています。これはインタラクティブなアプリケーションであり、そのほとんどは合理的に単体テストを行うことができません。存在する単体テストは、継続的インテグレーションサーバーで(メモリ破損時に)クラッシュします。もう1年以上前ですが、デバッガーで再現できないため、修正に取り掛かる人はいませんでした。また、CIサーバーが有用であるためには、実装されたことのないデータサンプルをフェッチしてテストする必要があります。
Jan Hudec 2013

1
これで、新しいコードで同様の警告を消音せずに既存の警告を効率的に消音する方法に要約できます。
Jan Hudec 2013

@Jan:あなたは本当にあなたが持っているいくつかのテストを修正することに悩むことができないと言っていますか?プログラミングフォーラムで?本当に?(SMH)
mattnz 2013

2
@mattnz:はい。テストは役に立たないので。そして、常になります。ビジネス情報システムの最も一般的なケースでは、自動化されたテストは優れていますが、インタラクティブなアプリケーションの種類にはあまり価値がなく、一部のサポート機能のデバッグにのみ使用することがあります。ほとんどのバグは、インタラクティブにのみテストできるコードで発生します。そのための自動化を書くことは想像できますが、コスト効率がよいかどうかはわかりませんが、多くの作業が必要になります。
Jan Hudec 2013

14

エラーとして扱われない警告は役に立たないと思います。あなたはそれらをたくさん得るので、誰もそれらを見ることに煩わされることはなく、彼らは彼らの目的を見逃しています。

私の提案は、それらすべてを修正し、それらをエラーとして扱い始めることです。
それらを修正することは恐ろしいように見えますが、私はそれができると思います。この作業を理解する優れたプログラマーは、各警告に対処する方法をすぐに理解し、非常に機械的かつ迅速に処理します。

私たちの会社でも同様のプロジェクトを実行しましたが、うまくいきました。コードの重要な部分に警告が表示されなくなりました。何千ものファイルについて話しています(警告の数はわかりません)。 。

この直後に、警告をエラーとして扱う必要があります。コードの一部に警告がない場合は、この部分のコンパイルフラグを変更し、新しい警告が入力されないようにします。これを怠ると、キノコのような新しい警告がポップアップ表示され、作業が無駄になります。

あなたが持っているかもしれない一つの懸念は、警告を修正した結果としてバグを導入することです。これは、おそらく、警告を修正するプログラマーが変更しているコードのほとんどを知らないためです。ただし、ほとんどの変更は非常に安全です。たとえば、関数プロトタイプまたはキャストを追加します。


2
+1:「エラーとして扱われない警告は役に立たないと思います。」:同意しますが、問題がないことについて警告を受けたいのはなぜですか?
ジョルジオ

1
@Giorgio警告は必ずしも修正する必要がないか、警告を修正するために利用できる時間/金額がない可能性があるためです。それらは技術的負債の一種です。これは、最終的に処理する必要がないという意味ではありませんが、敷物の下で掃除する必要がないことも意味します。残っている唯一の選択肢は、それらを用意することです。彼らはあなたをかゆくするためにそこにいるので、多分彼らは最終的に修正されるでしょう。
Robert Harvey

1
@ロバートハーベイ:私はあなたに完全に同意します。唯一のリスクは、警告を無視し始め、しばらくするとかゆみを起こさなくなることです。同じプロジェクトで何年も警告が表示されるのを見てきました。すべての開発者は、「しばらくすると修正されるはずだったと言っています。未来"。これらの警告に注意を払う人はもういませんでした。それらはマスタービルドログの通常の出力の一部になりました。このような状況をどうやって回避するのか私にはわかりません。
Giorgio

1
それらをすべて「今」の考え方で修正することの問題は、誤った修正と保守性の低いコードにつながることです-C ++では、型キャストが警告を簡単に消すことができる驚くべきことです(たとえば、署名/署名なし)。警告)。これはレガシーコードであるため、自動回帰テストが行​​われる可能性は低く、コードを変更すると不具合が発生します。「すべてを修正し、結果をb.gg.rに修正する」は正しいアプローチではありません。
mattnz 2013

@mattnz、警告を修正しながらコードを壊すことが、ここでの主な関心事です。しかし、他に方法はないと思います。それらを修正して将来のエラーをエラーとして扱うか、無視する(そして、警告されたバグをときどき見つける)かのいずれかです。
ugoren 2013

3

私はC ++コーディング標準を読んでいました:101のルール、ガイドライン、およびベストプラクティスと2番目のガイドラインは、「警告レベルを高くしてコンパイルをクリーンにする」ことを提案しています。それはあなたがプログラムの多くの警告とそれらの間のチーフがそうであるのを望まない多くの理由を概説します

  1. コードに潜在的な問題があります。
  2. サイレントで成功したビルドがあるはずです。そうでない場合は、実際の問題を見逃している可能性があります。
  3. 無視された良性の警告は、実際の危険を示す警告を不明瞭にする可能性があります

警告付きでコンパイルされるプログラムは正しいように見えるかもしれませんが、ある時点で発生する可能性のあるコードに実際の問題がある可能性があります。警告を分類し、優先順位を付け、時間がある場合は修正することをお勧めします。


+1:「警告レベルが高い場合のコンパイルのクリーンアップ」の場合:コンパイラーのヘルプをできるだけ多く使用する必要があると思います。
Giorgio

1

システムの予防保守を行うためにスプリント/サイクルを確保し、デッドコードをクリアし、警告を排除し、悪いコメントをクリーンアップするなどの方法をとるか、ソースが何か他のもののために触れられたときに警告を排除するポリシーを設定します。
私は警告を取り除くためだけに前者を自分で行うのではなく、そのようなサイクルが計画されている場合、それはワークロードの一部になるでしょう。その理由は、ファイルに何かを触れるとバグのリスクが発生し、製品の安定性にリスクが生じるためです。


2
スプリントを用意する余裕はありません。したがって、他の理由でソースに触れたときに警告を排除します。しかし、長い間触れられなかったソースがいくつかあり、触れるまでには長い時間がかかるため、これらのレガシービットから警告を伝える必要があります。
Jan Hudec 2013

@JanHudecは、これらの場合の警告の重大​​度を分析し、古いコードに再度アクセスして、選択したビットのクリーンアップを実行し、それを維持するためにリファクタリングする場合があります。そうしないと、古くなり、必要な場合でも人々はそれに触れることを恐れます。
2013

@JanHudec-システムの予防保守を行う余裕がない場合、警告を解決する時間がないようです。
ラムハウンド2013

@Ramhound:多少の管理はできると思いますが、それほど多くはなく、他の作業と並行して実行する必要があります。
Jan Hudec 2013

1

私も似たような状況なので、あなたの痛みを感じます。私が問題に取り組んだ方法は、一度に1つのモジュール/サブプロジェクトの警告を削除し、クリーンアップした後、モジュールに「警告をエラーとして扱う」(エラー)コンパイラフラグを設定することです。また、コンパイラーが異なる複数のオペレーティングシステム上に構築されている場合でも、1つのプラットフォームのみに焦点を合わせることにしました。最後に、コンパイルするサードパートライブラリについては、警告をオフにします。

これらの警告のいくつかを取り除くのは、言うよりもはるかに簡単です。たとえば、言及したsize_tと符号なしの問題では、キャストで警告を消すだけで整数オーバーフローが発生する可能性があります。そのため、場合によってはunsignedをsize_tに置き換えます。それ以外の場合は、実行時にオーバーフローを検出する必要があります。それはすべてケースバイケースです-非常に退屈で難しいです。

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