goto文
無条件ジャンプ
これまでプログラムは上から下へ逐次実行してきました。本来の手続き型言語のプログラムは「逐次」「判断」「繰り返し」で制御できますが、場合によっては何らかの要因によって無条件に指定位置に制御を移したい場合があるかもしれません。
無条件にプログラムの流れを変えるには goto 文(goto statement)を使用します。
goto 識別子 ;
識別子にはジャンプ先となる文に付けられているラベル(label)の名前を指定します。
goto 文のジャンプ先となる文には、あらかじめ goto 文で識別するためのラベルを指定しなければなりません。これをラベル付き文(labeled statement)と呼びます。
識別子 : 文
頭の識別子に、宣言するラベルの名前を指定します。命名規則は変数と同じです。宣言した識別子は変数と同じスコープを持ち、外部のブロックから認識することはできません。
また、ラベル名は変数名とは衝突しません。同じスコープ内に、変数名と同じ名前のラベルが宣言されてもエラーにはなりません。
int label; goto label; label: label = 10;
上記のコードではラベル付き文で宣言された label という名前が label 変数と衝突していますが、ラベルは独自の宣言空間を持つためエラーにはなりません。ただし、余計な誤解を招く可能性があるため、他の識別子と衝突するラベル名は避けるべきでしょう。
class Test { static void Main() { System.Console.WriteLine("Start"); goto label2; label1: System.Console.WriteLine("Label 1"); goto label3; label2: System.Console.WriteLine("Label 2"); goto label1; label3: System.Console.WriteLine("Label 3"); } }
コード1は単純な goto 文の例です。goto 文が実行されることで制御が指定したラベル付き文までジャンプし、途中の文が実行されていないことが実行結果から確認できます。
class Test { static void Main() { int count = 0; start: count++; if (count > 10) goto end; System.Console.WriteLine("count = " + count); goto start; end: System.Console.WriteLine("End of goto loop"); } }
コード2は、start ラベルから end ラベルの直前までのコードを count 変数が 10 になるまで繰り返し実行する処理を goto 文で実現したプログラムです。実際には、後述する繰り返し文があるため、goto 文でこのような処理を記述する必要はありません。
goto 文はプログラムの状況に関係なく無条件にジャンプします。初学者であれば、一見便利な機能に見えるかもしれませんが、現代の構造化プログラムの時代において goto は最も使ってはならない文と言えます。
これは、1968年に Dijkstra という人物が goto 文の問題点を指摘した本を出版したことからはじまり、現代では goto のような無条件分岐はプログラムの制御の追跡を困難にするという考えが一般的です。多くのプログラマが goto 文を使わない goto レスプログラムを支持しています。
switch文におけるgoto文
現代のプログラミングでは滅多に goto 文を使うことはありません。しかし C# の goto 文には無条件ジャンプ以外に重要な利用方法があります。それは switch 文でフォールスルーを行いたい場合です。
C# では switch ブロック内であれば、goto 文を使って任意の switch ラベルにジャンプできるのです。何らかの case ラベルまたは default ラベルに対応する分を実行した後、break 文で switch を抜け出すのではなく、別のラベルを実行したいような場合には goto 文を使います。
goto case 定数式 ;
goto default ;
case キーワードを加えた定数式を指定する goto 文は、指定した定数式の値に一致する case ラベルにジャンプします。同様に goto default は switch 文の default ラベルにジャンプします。
これら goto case と goto default は switch 文のブロック内でのみ利用できます。また、定数式には switch 文で指定できる型でなければなりません。指定した定数式の値に一致する case ラベルが存在しない場合もエラーになります。
class Test { static void Main() { int message = 0; switch (message) { case 0: System.Console.WriteLine("Case 0"); goto case 1; case 1: System.Console.WriteLine("Case 1"); goto case 2; case 2: System.Console.WriteLine("Case 2"); goto default; default: System.Console.WriteLine("Default"); break; } } }
コード3を実行すると、最初に case 0 が実行され、goto 文を用いて下の case ラベルにフォールスルーしていきます。最終的には全ての case と default を実行してプログラムは終了します。