ログイン
kid's world

デバッグ

これまで簡単なプログラムを作ってきましたが、必ずコンパイルが正常に終了し、実行が正常に行われるという保証はありません。ソースファイルを作るのは人間ですから、必ずといっていいほどミスが起こります。ミスが発生したときどうなるか、それを克服するにはどうすればよいかを本章では解説します。


バグとは

自分でソースファイルを作ってみて、どうしてもコンパイラがコンパイルをしてくれず、途方にくれたことは無いでしょうか。また、コンパイルができたとしても、意図したとおりに動いてくれないということは無いでしょうか。本に書いてあるコードを間違えずに打っているはずなのに…と思うこともあるかもしれません。

しかし、人間には気づかないような小さなミスがあっても、コンピュータは期待したとおりに動いてはくれないのです。コンピュータは素直な反面、非常に融通が利きません。このようなミスのことを「バグ」といい、人間が意図していないような動作をするとき、「このプログラムにはバグがある」などといったり、俗に「バグってる」などいいます。

本章では、わざとプログラムを間違えてみることによって、どのようにバグを克服、すなわち「デバッグ」すればよいかを解説します。

打ち忘れ

次のプログラムには誤りがあります。どこだか分かりますか?

#include <iostream>
using namespace std;

void main()
{
  cout << "test"
}

文は必ず「;」で終わります。これを一箇所でも書かなければ、エラーになってしまいます。このプログラムは文の終わりに「;」が無いのです。では、この誤まったソースファイルをコンパイルするとどうなるでしょうか。

Borland C++ 5.5 for Win32 Copyright (c) 1993, 2000 Borland
t.cpp:
エラー E2379 test.cpp 7: ステートメントにセミコロン(;)がない(関数 main() )
*** 1 errors in Compile ***

Borland C++では、このようなエラーメッセージが表示されました。よく見てみると、「test.cpp」の7行目でエラーになったと書いてあります。そのエラーは

「ステートメントにセミコロン(;)がない」

というものです。実際にセミコロンが無いのは6行目ですが、コンパイラが7行目までソースファイルを読んだときにそれに気づいて、コンパイルを中断したということになります。

打ち間違い

つぎに、coutを打ち間違えるとどうなるでしょうか。

#include <iostream>
using namespace std;

void main()
{
  cuot << "test";
}

非常に長いプログラムの中にこのようなミスがあると、見つけるのが大変ですね。コンパイルしてみると、

Borland C++ 5.5 for Win32 Copyright (c) 1993, 2000 Borland
t.cpp:
エラー E2451 test.cpp 6: 未定義のシンボル cuot(関数 main() )
*** 1 errors in Compile ***

というエラーメッセージが表示されました。すなわち、6行目で、

「cuotなんて知らん(未定義のシンボル)」

とコンパイラが言って、中断したということになります。

このように、コンパイラが表示するエラーによって、ある程度のミスは発見して、修正することができます。

対応関係が取れていない

次のプログラムにもミスがあります。

#include <iostream>
using namespace std;

void main()
{
  cout << "test;
}

すぐに気づきましたか? コンパイルしてみましょう。

Borland C++ 5.5 for Win32 Copyright (c) 1993, 2000 Borland
t.cpp:
エラー E2380 t.cpp 6: 文字列または文字定数が閉じていない(関数 main() )
エラー E2379 t.cpp 7: ステートメントにセミコロン(;)がない(関数 main() )
*** 2 errors in Compile ***

文字列が閉じていないとのエラー出ました。文字列は必ず「"」で囲まれていなければならないのですが、文字列の右側に書くべきところに「"」が無いために、コンパイラはどこまでが文字列なのか分からなくて、コンパイルを中断したのです。

C++言語の中で、このような対応関係をもつ記号はたくさんあります。たとえば、関数定義の「{」と「}」や、引数の「(」と「)」などです。どちらかがかけてしまうというのは意外と多く起こることで、しかも、しばしばコンパイラがそのことに気づかずにわけのわからないエラーメッセージを表示するため、厄介なミスです。

コンパイルができても…

10÷3の計算結果を表示したくて、次のようなプログラムを書いてみました。

#include <iostream>
using namespace std;

void main()
{
  cout << 10 / 3 << endl;
}

コンパイルはうまくとおりました。早速実行です。どのような結果が出たでしょうか。予想に反する答えが出たと思います。

「10÷3」

を計算したかったのですが、肝心の答えは

「3」

となってしまいました。「3.333333…」とはならず、小数点以下が表示されません。これもバグです。コンパイラがバグっているわけではなくて、いま書いたこのプログラムにミスがあるのです。どうしてこうなったのかは次章で説明しますが、このように、仮にコンパイルができたとしても、意図したとおりの結果が出ないこともあります。そして、ソースプログラムを書く時間よりも、このようなバグをつぶす、「デバッグ」にかける時間のほうがたいてい多くなります。この種のバグを克服するには、知識と、注意深さが要求されます。非常に大変ですが、これがプログラミングの現実です。

書くプログラムが複雑になればなるほど、このようなコンパイルできるのに意図したとおりに動いてくれないというバグが増えていきます。この場合、プログラマのC++言語の知識にあいまいなところがあるか、プログラマが想定していた処理の手順、すなわちアルゴリズムが誤まっている場合がほとんどです。今はまだ分からないかもしれませんが、どうしてもうまく動いてくれないときは、まずこの2点を疑ってかかってみてください。

それでもダメなときは、いちどコンピュータから離れて、コーヒーを飲んだり散歩したりして気分転換して帰ってくると、なぜか意外と簡単にバグが見つかる場合があるようですよ。

まとめ

キーワード

広告


©Toshio Koide 1996-2007.

目次

リンクについて

リンクは御自由にどうぞ。

メール

mail.gif

広告