コラム17. :C言語と「goto」
goto文とスパゲティ・コード
C言語が出現する以前のプログラミング言語の多くには、goto(ゴートゥー)文という、プログラムの任意の場所に飛んでいくことができるステートメントが普通に使われていました。
このgotoは、マシン語で任意のアドレスから他のアドレスへジャンプする命令に該当する命令を、高級言語につけたものですが、これを用いると、非常に大きな問題がありました。その問題とは、プログラムが「ぐちゃぐちゃ」になってしまうということでした。
goto文を用いると、最初のうちはいいのですが、必要に応じてプログラムを改造していくうちに、プログラムの流れが、あっちに行ったり、こっちに行ったりと、非常に入り組んできてしまうのです。このように、処理の流れや構造を把握しにくく、修正や機能の追加が困難になったソースコードのことを、その様子からとってスパゲティ・コードと呼ぶようになったのです。
C言語とgoto
このような問題に対処するために考え出されたのが、構造化プログラミングという考え方でした。コラム14で紹介した通り、「一つの入口と一つの出口を持つプログラムは、順次・選択・反復の3つの論理構造によって記述できる」という考え方で、C言語はこの考え方を適用した言語でした。
C言語では分岐する処理を関数にまとめたりすることにより、構造がすっきりして、goto文を用いなくても複雑な処理を行うプログラムを記述できるようになりました。そのため、プログラミングの効率が飛躍的に良くなったということはすでにふれました。
これによりC言語は、プログラミングのメンテナンス性が高くなり、goto文を用いて処理の流れを変えていた従来のプログラミング言語よりも格段に大規模なプログラムの開発を行いやすくなったのです。
C言語とgoto
では、このC言語にgoto文がないか…というと、実はそんなことはありません。実は、C言語には、しっかりとこの「goto」文が残っているのです。以下のプログラムを見てください。
リスト1:C言語によるgoto文の入ったプログラムの例#include <stdio.h> void main(){ int i = 0; loop: printf("%d ", i); i++; if (i < 3) goto loop; printf("¥n-- end --¥n"); }
-- end --
「loop:」と書かれている部分を、ラベルといい、:の前がそのラベルの名前である、「ラベル名」と言います。goto文の後に、このラベル名を書くと、プログラムはこの部分にジャンプします。
そのため、このプログラムは、iが3になるまで、iのインクリメントを続けてラベル「loop」の箇所に戻り、最後に「-- end --」という文字列を表示して終了することになります。
なぜC言語にgotoが?
このようにC言語に存在するgoto文ですが、実はこのgoto文、仕様には存在するにもかかわらず、使用することは推奨されていません。
ではなぜ、C言語にgoto文が存在するのでしょうか?せっかく構造化プログラミングができる言語になったC言語なのに、なぜわざわざ「過去の遺物」のようなgoto文が残っているのでしょうか?そのはっきりした理由はわかりませんが、おそらくそれはC言語が誕生したときの「やむにやむにやまれぬ理由」があったと思われます。
時代背景による制限
理由の一つは、そのころのコンピュータおよびCコンパイラの「性能の限界」でしょう。
goto文を使わずに3つの基本構造による代替を行うと、理論上は同じ処理であったとしても、実際にはプログラムの実行速度や記憶容量の点で性能が劣ってしまいます。その当時のコンピュータは現在のものに比べ、処理スピードも、メモリの面でも大きく見劣りしていました。そのため、この欠点は致命的で、その問題点を少しでもかばーするために、goto文が残された、ということが考えられます。
そしてもう一つの理由は、やはりその当時のプログラマーがgoto文を除いたプログラムの記述になれていなかった…ということでしょうか。また、ドナルド・クヌースが著書「文芸的プログラミング」の中で述べているように、特殊な場合にはgotoを使った方がプログラムの正当性を証明しやすくなるという考え方も存在しました。
その後、Javaのように「そもそもgoto文が存在しない」ような言語も存在しますが、D言語のように新しい言語でも必ずしもgoto文は廃止されていないことから、まだまだこの文を必要としている人はいるのかもしれません。