わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

デバッグしよう(2)〜構文エラーをなくす

まずは,問題なソースコンパイルしてみます.ファイル名はちょっと長いですが,relatively_prime.cです.コンパイルCygwin上のGCC 3.4.4を使用していますが,あまりコンパイラには依存しないと思います.ただし,都合により,エラーメッセージは英語で出力することにします.

$ env LC_ALL=C gcc relatively_prime.c 
relatively_prime.c: In function `main':
relatively_prime.c:12: error: `frag_rp' undeclared (first use in this function)
relatively_prime.c:12: error: (Each undeclared identifier is reported only once
relatively_prime.c:12: error: for each function it appears in.)
relatively_prime.c: In function `gdc':
relatively_prime.c:25: error: parse error before "if"

プログラミングを習い始めたころだと,この出力にびっくりして,とにかくうまくいかなかったんだ(先生のやり方,あるいは本に書かれていることと違う)と思って,ソースファイルを見直すかもしれません.
しかし,ソースファイルの「どこ」を見れば,効率よくバグを見つけ,退治できるかが,上のエラーメッセージに書かれているので,急がば回れ,少し腰を落ち着けて,見てみましょう.分からない単語は,辞書を引かなくてもいいのです.
構文エラーは2箇所あるようです.それがどこで分かるのかというと,

  • relatively_prime.c:12: error
  • relatively_prime.c:25: error

です.一つめは,「relatively_prime.c の 12行目 に エラー あり」,もちろん二つめは,25行目あとは同じというものです.
じゃあ12行目,25行目を見ればそこにミスがあるのか,と見に行くのは,気が早いというものです.エラーメッセージの中の「frag_rp」と「if」を頭に入れておき,それから,ソースを見直します.
12行目は次の通り.

  if (frag_rp) {

これがもし正しければ(実際には間違いなのですが,いわば背理法です),frag_rpという名前の変数がある…すでに宣言されているはず…です.2つ上の行を見ますと,

  int flag_rp = relativelyprime(x, y);

となっていまして…宣言している変数は,flag_rp.12行目は,frag_rp.ここに,変数名の間違い(背理法で言えば,矛盾!)がありました.
この2つの変数を同じ名前にすればいいのですが,さてどちらを変更しましょうか….
この件は,flag_rpという変数名を使うべきです.というのも,プログラミングの世界でフラグというのは「(フラグ=旗=flagが)立っているか,そうでないか」,言い換えると「1か0か」を保存するための変数としてよく用いられるからです*1
12行目のfrag_rpをflag_rpに書き換えて*2,25行目にもあると言っているエラーには手をつけずに,コンパイルすると…

$ env LC_ALL=C gcc relatively_prime.c 
relatively_prime.c: In function `gdc':
relatively_prime.c:25: error: parse error before "if"

12行目のバグは,退治できました.では,テキストエディタに戻って,25行目を見ましょう.

  if (r == 0) {

ifの構文は間違っていませんし,変数rは,2行前で宣言されています.この行だけを見ると,問題なさそうです.
「parse error before "if"」と書いていますので,「"if" の前」を含めて見ることにします.

  int r = a % b

  if (r == 0) {

変数rの宣言で,最後にセミコロンをつけ忘れていました!

  int r = a % b;

  if (r == 0) {

として,改めてコンパイルすると,「relatively_prime.c:12: error」「relatively_prime.c:25: error」から始まるエラーはなくなりましたが,新たなエラーが出てきました.
本日はここまで.

  • まとめ
    • エラーメッセージの中に「ファイル名:行番号」があれば,その行とその行までを見直す
    • エラーメッセージの中に,識別子や," "で囲まれているものがあれば,そこに着目する
    • 行番号は「そこでエラーが起こりました」であって,「そこの行を修正しないといけません」ではない
  • 知っておこう英語表現
    • undeclared : 宣言されていない
    • parse error : 構文解析時に発生したエラー,構文エラー.ここのparseは,動詞ではなく名詞(の形容詞的用法)です.

*1:細かいことをいうと,もとは0だけど,何らかのアクションにより1になることがある,ということを含みます.今回のプログラムでは,最初に代入した値から変わらないので,そういう意味でflagは適切でないかもしれません.もう一つ余談ですが,3つ以上の値をとり得る変数にflagは適切ではなく,かわりにstatusとすべきでしょう.

*2:「_rp」について説明しておくと,このプログラムはフラグ変数が一つだけなので「flag」とだけするのでもいいのですが,一つのブロックに複数のフラグ変数を使用しないといけないときに,最初がflag,次は…flag2なんてのにすると,何がなんだかわからなくなります.ということで,最初から,こういう接尾辞をつけている,ということです.