PC-Lint Static Code Analyzer

「長い箱」に問題を残さないために、静的コードアナライザーを使用した私の経験についての話を続けます。 ( ここここから始め ください )。



Klocworkを試した後、経営陣に興味を持たせようとしましたが、3万ユーロの価格が主要な停止基準となり、他のすべてはもはや重要ではなくなりました。



しかし、ある会社は、ある種のコードアナライザーのライセンスを既に取得していることを突然思い出しました。 このアナライザーは、PC-Lintであることが判明しました。 誰もそれを使用していないことがわかったので(最後まで読んだ後、その理由は理解できるでしょう)、彼らは私にライセンスを与えてくれました。



まあ、システムはKlocworkの正反対であることが判明しました。 コマンドライン、パラメーターまたは構成ファイルを介したすべての設定から開始し、分析用のファイルのリストを手動で準備する必要があります。 確かに、Visual Studioとのある種の統合がありましたが、ファイルのリストの作成を避けることしかできませんでした。 構成ファイルは、テキストエディターで「手書き」で書き込む必要がありました。



出力はテキストファイルです。 Visual Studioから開始する場合-スタジオコンソールをクリックし、そこからクリックして問題の疑いのある場所に移動できます(すでに簡単です!)



PC-Lintの最大の問題は、メッセージの数です。 デフォルト設定の比較的小さなプロジェクトで、彼は23,000以上のコメントを発行しました! 最も重要な34個の問題を表示し、同時に「オフ」にするのに数日間費やした後、コメントの総数を5万5千個に減らすことができました。



そしてもちろん、そのようなヒープでは、実際のバッファオーバーフローまたは初期化されていない変数の使用を示すいくつかの本当に重要なポイントが簡単に失われる可能性があります。



そしてまさにこの理由で、それを買った人はツールの使用をやめました。 数千の警告を数日かけて掘り下げながら、いくつかの実際の重大な問題を発見し、コードスタイルをわずかに改善して、使用を中止しました。



特定のタイプのすべてのメッセージのみを「オフ」にすることができます。特定のメッセージを誤検知としてマークする可能性はありません。



もちろん、ビルドからビルドへの追跡はありません。 メッセージの総数にのみ集中できます。



ヘッダーファイルで見つかった問題は、このファイルが接続されるたびに複製されます。 ファイルが10回接続されると、10回すべてPC-Lintは内部で見つかったすべての問題に関するメッセージを表示します。 そして、彼がスタジオ自体のファイル、特にSTLコンテナの実装でも問題を簡単に見つけることを考えると...



同時に、どのように問題が発生するかについても示されていません。 つまり たとえば、彼はこの場所で初期化されていない変数を使用することが可能であると報告することができますが、どのような状況でそれが起こるか、自分で推測する必要があります(関数の開始からすべてのブランチを介して問題点までの完全なパスを示すKlocworkとは異なります)。



さらに、ローカルでのみ機能します。 チームで作業する場合、すべての参加者がそれを実行する方法はないため(もちろん、参加者ごとに個別のライセンスが購入されていない限り)、見つかった問題を簡単かつ迅速に他の人に報告する方法はありません(テキストのコピーと貼り付けのみ)。



もちろん、PC-Lintとプラスがあります。



特定の条件下では、メッセージの数はプラスと考えることができます。 ほとんどのメッセージはスタイルに関連しており、潜在的な問題を示すことはほとんどありませんが、ほとんどすべてのメッセージには常識が欠けていることを認識する価値があります。 そして(理論的に)PC-Lintが修正するために提供するすべてを修正すると、コードは明らかに良くなり、より理解しやすく、読みやすくなります。 しかし、インターネット上の誰かが言ったように、「リントではなくCでプログラムしたい!」



「化粧品」の発言の例:



それは:

calib_offset = (int32)(full_offset / full_gain * 100000);
      
      





PC-Lintは、ここで読むことのあいまいさを見ます:a / b * c-これは(a / b)* cまたはa /(b * c)ですか?



したがって、次のようになりました。

 calib_offset = (int32)( (full_offset / full_gain) * 100000);
      
      





私の意見では、読みやすさが向上しました!



プロジェクトがゼロから始まり、大きすぎない場合は、特定の要望があれば、PC-Lintから「ゼロ問題」アプローチを取得することもできます。 最初の起動時にプロジェクトが完了に近づいた場合、「ゼロの問題」を達成することはほとんど不可能になります。



他の利点の中で、私は以下を区別できます。





そして最後に-いくつかの本当に見つかった問題領域:



それは:



  switch (SocketID) { case SOCKETID_1: case SOCKETID_2: break; case SOCKETID_3: doSomething(); break; case SOCKETID_4: doSomethingElse(); case SOCKETID_5: doSomethingElseSimilar(); case SOCKETID_6: doAnotherThing(); break; default: return ERR_SERVICE_NOT_SUPPORTED; }
      
      





次のようになりました:



  switch (SocketID) { case SOCKETID_1: case SOCKETID_2: break; case SOCKETID_3: doSomething(); break; case SOCKETID_4: doSomethingElse(); break; case SOCKETID_5: doSomethingElseSimilar(); break; case SOCKETID_6: doAnotherThing(); break; default: return ERR_SERVICE_NOT_SUPPORTED; }
      
      





誰かが突然気付かなかった場合、単語の区切りが2回欠落していました。



 void main_task(void *p_arg) { int status; // somewhere below… status = memory_init(&memory_config[0], memory_heap, sizeof(memory_heap)); // and later “status” in never used… }
      
      





このコードに関するコメントはかなり文体的です-「ステータス変数の値はどこにも使用されていません」、しかし、私の意見では、それほど無意味ではありません-そのようなコードは、memory_init関数の結果がどこかに考慮されるという誤った信念を作成しますが、そうではありません。



そして、未使用の変数を宣言して結果を明示的に破棄することなく、このようなコードを書き直す方がはるかに「正直」です。

 void main_task(void *p_arg) { // some code… memory_init(&memory_config[0], memory_heap, sizeof(memory_heap)); // some other code }
      
      





もちろん、失敗した場合に結果を確認し、必要なアクションを実行する方がより正確ですが、...プロジェクトが初期段階であり、アプリケーションアーキテクチャの変更がまだ非常に簡単であり、プロジェクトが既に完了しており、この場所で例外処理が行われているときは良いです最初はアーキテクチャ的に定められていませんでした(結果を確認し、次に何を確認できますか?失敗を通知し、呼び出し関数に例外処理メカニズムがない場合、次に何ができますか?)。



そのため、「アナライザーからの警告をゼロにする」という要件に加えて、定期的に(理想的には各ビルド後に)実行される静的コードアナライザーが必要です。



もちろん、有能な開発者、コードレビュー、およびその他の開発管理の手法と手法に代わるアナライザーはありません。 ただし、適切に使用すれば、チーム全体の生活が確実に楽になります!



All Articles