デバッグの仕組みを知る
さて、様々なプログラムを作ってきましたが、どうだったでしょうか。間違いなくコードを記述することができたでしょうか。しかし、人間には誤りがつきものです。コードを作成していくときには、様々な誤りを犯してしまう可能性があります。
例えば、C言語の文法を誤ったために、コードをコンパイルすることができないことかもしれません。また、一見うまく動作しているプログラムであっても、考えていた動作とは違う動きをすることがあるかもしれません。
プログラムの中の誤りを、バグ(bug)といいます。プログラムを完成させるためには、、プログラムに含まれるバグをなくしていく必要があります。コード中のバグを探し、訂正する作業はデバッグ(debug)と呼ばれてます。
C言語の環境は、デバッグ作業を行うために、いくつかの便利な機能を備えています。そこで、最後のこの節では、C言語のデバッグ機能について紹介しておくことにしましょう。
条件付きコンパイルの仕組みを知る
デバッグ作業の1つとして、変数の中身がどのような値をとっているかを確認することがあります。プログラムの中には、実行することができたとしても、考えていたものとは違う結果となってしまう場合があります。この時、変数の中身を画面などにコードを記述しておき、おかしな値が格納されていないか確認する作業を行うのです。
しかし、バグを訂正したあと、この画面表示のコードは余計なものとなります。ユーザーに配布する最終的なプログラムをコンパイルする段階では、デバッグ用のコードは不要になるのです。
そこで、C言語のプリプロセッサは、状況に応じてコンパイルする指定を用意しています。これを、条件付きコンパイル(conditional compilation)と呼びます。次のコードを見てください。
#include <stdio.h>
#define DEBUG //①マクロを定義する
int sample17()
{
int i;
int sum = 0;
for (i=1; i <= 5; i++)
{
#ifdef DEBUG //②マクロを定義されいる場合に...
fprintf(stderr,"変数sumの値は%dとなっています。\n", sum); //③このコードをコンパイルする
#endif // DEBUG
sum = i + sum;
}
printf("1~5までの合計値は%dです。\n", sum);
return 0;
}
実行結果:
変数sumの値は0となっています。
変数sumの値は1となっています。
変数sumの値は3となっています。
変数sumの値は6となっています。
変数sumの値は10となっています。
1~5までの合計値は15です。
このコードでは、次のような記述を行っています。
#define DEBUG //マクロを定義する
#ifdef DEBUG //マクロを定義されいる場合に...
fprintf(stderr,"変数sumの値は%dとなっています。\n", sum); //このコードをコンパイルする
この#ifdef~#endifという指示は、条件に応じてコンパイルするコードを変える機能を持っています。
このコードでは、まず①で、「DEBUG」というマクロを定義しています。このマクロには置き換える文字列を指定していません。ですが、これもマクロの定義です。
そして、②の#ifdefでは、DEBUGマクロが定義されているかどうか調べています。もしDEBUGマクロが定義されていれば、#ifdef~#endifまでの間の文がコンパイルされるようになっています。ここではDEBUGマクロが定義されていますので、変数の中身を表示するコードがコンパイルされるわけです。
さて、デバッグ作業によって、変数の中身が正しいことが確認できたとしましょう。デバッグ作業が終わり、実際にユーザーに使ってもらうプログラムをコンパイルするときには、①で定義したマクロを削除します。削除後にもう一度コンパイル・実行してみてください。実行結果は次のようになります。
1~5までの合計値は15です。
今度は変数の中身が表示されていません。マクロが定義されていないために、#ifdef~#endifの間の部分のコードがコンパイルされなかったのです。条件付きコンパイルでは、このように条件に応じてコンパイルする部分を変えることができるのです。
なお、ここでは変数の中身を表示するために、fprintf()関数を使ってます。最初の引数であるstderrは、標準エラーと呼ばれる装置に結び付けられているストリームです。標準エラー出力とは、デバッグ情報などを表示するための装置を指します。ここでは標準出力と同じ画面装置となってますが、実際環境によっては別の場所であることもあります。その際には、標準エラー出力として指定されている場所に、変数の内容が表示されることになります。
このように、条件付きコンパイルの仕組みによって、デバッグに必要なコードを、デバッグ時にだけコンパイルすることができるようになります。プログラムの完成後にはデバッグ用のコードを除くことができるので便利です。条件付きコンパイルには、以下のようなバリエーションがあります。確かめてみると良いでしょう。
条件付きコンパイル(#ifdef)の構文
#ifdef マクロ
文;
…;
#endif
条件付きコンパイル(#ifndef)の構文
#ifndef マクロ
文;
…;
#endif
条件付きコンパイル(#if)
#if 式1
文;
…;
#elif 式2
文;
…;
#else 式3
文;
…;
#endif
組み込みマクロを使う
最後にもう一つ、デバッグ作業において便利な仕組みを紹介しておきましょう。C言語の環境には、次の標準的なマクロが定義されています。
マクロ名 | 置きかえられる内容 |
---|---|
__LINE__ | ソースファイルの行番号 |
__FILE__ | ソースファイルのファイル名 |
__DATE__ | ソースファイルのコンパイル時の日付 |
__TIME__ | ソースファイルのコンパイル時の時刻 |
__TIMESTAMP__ | ソースファイルの最終変更時の時刻 |
__STDC__ | ANSI Cに対応いれば1 |
これらのマクロは、ソースファイルに関する情報を表すものです。#defineを使って定義しなくても、コード中で使うことができるようになっています。早速いくつかのマクロを利用してみましょう。
#include <stdio.h>
int sample18()
{
int i;
int sum = 0;
fprintf(stderr, "ソースファイル名:%s\n", __FILE__);
fprintf(stderr, "作成日付:%s\n", __DATE__);
fprintf(stderr, "作成時刻:%s\n", __TIME__);
for (i = 1; i <= 5; i++)
{
sum = i + sum;
}
printf("1~5までの合計値は%dです。\n", sum);
return 0;
}
実行結果:
ソースファイル名:E:\099_Technology\C\c_learn_jp\lesson12\lesson12.c
作成日付:Jul 5 2021
作成時刻:21:58:30
1~5までの合計値は15です。
組み込みマクロを使うことで、ソースファイルの名前・作成日付・作成時刻を表示しました。ソースファイルに関する情報を入手することができるわけです。条件付きコンパイルと組み合わせれば、デバッグを行う際に役立てることができるでしょう。このように、C言語環境に提供されている機能を使って、デバッグ作業を行いやすくすることができるのです。
コメント