バグとデバッグ
コンピュータプログラムに潜む不具合のことをバグと呼ぶ。実行すると強制終了してしまうように、非常に明確に具現化するバグもあれば、正常に動作しているようで実は計算結果が誤っていたり、普段は正常に動作しても特定の入力に対しては正しく処理できなかったりといった、なかなか発見しにくいバグもある。
プログラムの開発は、プログラム設計、コーディング、コンパイル、リンク、そして実行の手順を踏んで行われる。おのおのの段階で 発生したエラーがそのまま実行ファイルに残ってしまうと、それがバグとなり、当然のことながらプログラムは正しく動作せず、大切なデータを破損するなどの最悪の結果を招くこともある。
プログラムからバグを取り除く作業をデバッグと言い、それを支援するプログラムがデバッガである。
エラーの種類
バグの無いプログラムを作成することは、とても重要なことであり、かつとても大変な作業である。やみくもに場当たり的な処置を施しても事態は改善しない。まず、プログラム開発の過程を整理した上で、どの段階でどのようなエラーが生じるかを、しっかりと理解しておいてほしい。
エラーの種類を大別すると以下のようになる。
設計時のエラー
- 仕様のエラー
プログラムの外部仕様を設計する段階で発生するエラー。入力される値の範囲の予想を誤っているなどの場合である。アルゴリズムの設計に入る前に、実行時に予想されるさまざまな事態を、思慮深く考察する必要がある。
- アルゴリズムのエラー
正しい仕様を設計したものの、その仕様を実装するのに用いるアルゴリズムにエラーが含まれる場合がある。コンパイル時のエラー
コーディングを終えたプログラムを、コンパイラが翻訳する時に発生するエラーがコンパイルエラーである。コンパイルエラーには、構文のエラーや、代入や関数呼び出し時の変数型の不整合などがある。
コンパイラは言語仕様に基づいた構文規則にしたがって解釈・翻訳していくので、記述したソースコードがこれにのっとっていない場合にはエラーメッセージを出力し、翻訳を中断する。 コンパイルエラーを防ぐには、まずコンパイルに使用する言語の仕様を、しっかりと理解しておく必要がある。
また、C言語処理系でのコンパイルは、プリプロセス、コンパイルの2段階で行われる(課題2の資料参照)ことを理解しておくことも重要である。
リンク時のエラー
コンパイラによって生成されたオブジェクトファイルを結合するときに生じるのがリンクエラーである。呼び出す関数名の記述を間違えていたり、プログラムに必要なライブラリをリンカに指定していない場合に発生する。前者の場合には、関数プロトタイプ宣言を正しく使用することにより、防ぐことができる。
実行時エラー
完成した実行ファイルを動作させたときに生じるのが実行時エラーである。
実行時エラーのひとつに、プログラムの異常終了がある。ゼロによる除算エラーや、メモリ操作の誤りによるアクセス違反などによってプログラムは異常終了する。適切なエラー処理を怠っていたり、ポインタ(演習IIで学ぶ)の操作を誤っていることが主な原因である。プログラムは、いかなる状況においても (たとえ、自分専用のプログラムであったとしても)異常終了してはならないことを肝に命じておいてほしい。
実行時のエラーは、常に起きるとは限らないものが多い。入力されたデータの値が想定した限界値の境界だった場合や、空きメモリ容量が少なくなった場合などに、突然現れるバグもある。また、この原因は、仕様のエラーから引き起こされていたり、単なるコーディングミスによるものなどさまざまである。可能な限りいろいろな可能性を考え、注意深く設計し、十分なテストを行うことが大切である。
バグを入れない工夫
コンパイル・リンク時のエラーは、処理系により検知されるので、それがそのままバグとなることはない。逆に言うと、潜在的なバグは、可能な限りコンパイル・リンク時にエラーとして健在化させるよう工夫すると良い。
たとえば、 Cプログラマがわかっていながら、まま犯してしまうミスのひとつに、比較文を書くところを代入文としてしまう例がある。
誤り if (i = 0) {
.....期待した動作 if (i == 0) {
.....このとき、比較文を書くときには、0 == i のように、常に定数を左辺に書く習慣をつけておくと、誤ってイコールをひとつ打ち損ねた場合には、定数には代入できない旨のコンパイルエラーが発生し、誤りに気がつくことができる。
![]()