プログラマーからいものを集める

プログラマの皆さん、コメントの中でエラーの例を共有することをお勧めします。エラーの例は、プログラムの作成段階でもプログラム内で見つけることができます。 確かに誰もが、1時間のデバッグの後にブルーパーを修正した後、「ええ、コンパイラーはここで警告を出さなかった」とため息をついた。



まず、C ++プログラムで作成されたエラーパターンに興味があります。 しかし、私は故意にこの投稿を「C ++」セクションに入れませんでした。 他の言語からのエラーの例を挙げてください。 多くの場合、間違いを考慮して、別の言語で対応するものを思いつくことができます。



一般的なタイプのエラーを診断するための新しい一意のルールセットを作成するには、エラーが必要です。 本当に関連性があり、抽象的なアプリケーションではなく、私たちに与えられた感覚でエラーを見つけるルール。 テキスト内で誤って横になっている三角形を探すのは面白くありません。 トライグラフに関連する間違いを見たことがありません。 そして、ここにタイプミスがあります。この場合、行をクリアするためにstr.clear()の代わりにstr.empty()が書き込まれます。 たとえば、私はそのような例をここに書きました 。 そして、結局のところ、そのようなエラーは既存のツールではありません! したがって、古いものの繰り返しではなく、新しいものを作成するパスをたどっています。



次に、聞きたいミスとその方法について説明します。







最も一般的なタイプミスの例から始めましょう。

 ダブルa;
 a = 1.536; 


ピリオドの代わりに、カンマが誤って書き込まれます。 結果として、この行は「(a = 1)、536;」と同等です。 変数 'a'は値1を取ります。コンパイラは自然にサイレントのままです(少なくともVisual C ++)。



多くの人が、そのような間違いを犯すことができるのは男子生徒だけだというトピックについて、すでに頭の中でコメントを準備していると思います。 無駄だ。 誰もそのようなエラーの影響を受けません。 この状況は、私が知っている最高のプログラミングスペシャリストの1人によって説明されました。 これはタイトル「Programming Wizard、Intel Black Belt」の所有者であるDmitry Vyukovです。 多くの記事とプロジェクトRelacy Race Detectorの著者。



この同じコンマに関するRSDN Webサイトでのメッセージは次のとおりです。 当然、この投稿に注意を払うしかありませんでした。 エラーは非常に現実的で関連性があり、ソースコードの静的分析によって検出できます。 このようなエラーの診断はPVS-Studioで実装されました。



さらに進みましょう。 std :: remove()は要素を削除せず、それらをシフトするだけであることを忘れがちです。 その結果、erase()関数と組み合わせて使用​​する必要があります。 Elena Sagalaeva(ブログ「Alena C ++」の著者)は、このことについて「メモ: std :: removeおよびstd :: remove_ifは実際には何も削除しません 。」



これは、一般的で美しく関連性のある高レベルのエラーでもあります。 私は彼女が本当に好きです。 実際のアプリケーションでは、次のようになります(ZThreadsライブラリ):



  void unregisterThread(){
   Guard <TaskQueue> g(_taskQueue);
   std :: remove(_threads.begin()、_ threads.end()、ThreadImpl :: current());
 } 


このフラグメントは、Alyonaの記事を読んだ後に作成された対応するチェックを実装した後、PVS-Studioによって発見されました。



私自身は、私の個人的な経験に基づいて次のルールを思いつきました。 それは起こりました、そして今、私はタイプミスをして、間違った変数名を使用することが起こります。 これらのエラーの一部は自動的に検出できます。 たとえば、ある変数に行の異なる値が割り当てられている場合は疑わしいです。 PVS-Studioを使用して適切な診断を実装した後、たとえばWin32 ++ライブラリで次のようなエラーがすぐに発見されました。



 クラスCSize:public SIZE
 {
   ...
   CSize(POINT pt){cx = pt.x;  cx = pt.y;  } 


静的分析のルールを構成できる別の議論の例を示します。 ここでは、長い間、基本クラスへのポインタを介して派生クラスの配列を操作できないことを人々は理解できませんでした。 そして、通常起こるように、「バグの多いコンパイラ」を非難しました。 議論の中で、削除演算子の議論は混乱を招く可能性があるため、例を挙げます。



 クラスA
 {
   int a;
 };

クラスB:パブリックA
 {
   int b;
 };

 void FOO()
 {
   B配列[5];
   A * p =配列;
   p [3] .a = 1;  //私たちはどこで理解していないと書いています
 } 


クラスAとクラスBのサイズは異なるため、配列[i]とp [i]はメモリの異なるセクションにアドレス指定されます。



これは、静的解析が多くの神経細胞と時間を節約できる非常に良い例です。 このようなエラーを診断するためのルールはPVS-Studioでまだ作成されていませんが、開発計画に書かれています。



フォーラム、記事、個人的な経験での議論に基づいて、興味深い分析ルールを作成する方法のさまざまな例を説明しました。 あなたの例や同様の例へのリンクを共有していただければ幸いです。



PS



記事にコメントする機会がない場合は、karpov [@] viva64.comまたはお問い合わせフォームからご連絡ください



All Articles