制御構造
出典: フリー百科事典『ウィキペディア(Wikipedia)』
制御構造あるいは制御フローとは、計算機科学において文や命令を実行する順番を意味する。プログラミング言語では、制御構文とは命令の実行順を通常の逐次実行以外の順番に変化させる命令である。制御構造は一般にひとつのスレッド内の処理の流れを指し、明確な逐次命令実行に依存する。
制御構文の種類は言語によって様々だが、大まかに以下のように分類できる。
- 別の文から実行を継続する(ジャンプ)
- 何らかの条件が成立したときだけ文の並びを実行する(選択)
- 文の並びを繰り返し実行する(ループ、コードの先頭に近いほうへのジャンプと等価)
- 離れた箇所の文の並びを実行し、元の場所に制御を戻す(サブルーチン)
- プログラムを停止し、その後の実行を防ぐ(停止)
割り込みは制御フローを変化させる別の機構であり、サブルーチンに似ているが、言語内の制御構文ではなく外部のイベントなどの結果として発生するものである。自己書き換えコードも制御フローを変化させることができる。ただし、それを制御構文として明確化することはほとんどない(例外としてCOBOLの ALTER がある)。
機械語やアセンブリ言語では、制御命令はプログラムカウンタを変更する働きを持つ。多くのCPUでは制御命令としてジャンプ命令(条件付きおよび無条件)しか用意されていない。プロセッサの設計によっては、例えば投機的実行やアウト・オブ・オーダー実行など命令の厳密な逐次実行が弱められているため、制御フローが複雑化している。高級言語のコンパイラは様々な制御構文を限定された命令を使った等価な機械語のコードに変換し、自然な逐次実行の振る舞いを保持するようになっている。
目次 |
[編集] 基本構文
[編集] ラベル
ラベルとは、ソースコード上の固定の位置を示す何らかの名前(あるいは数値)であり、ソースコード上の他の箇所の制御構文で参照される。ソースコード上の位置を記録する以外の効果はない。
行番号は一部の言語(FORTRANやBASIC)でラベルの一種として使われ、負でない整数がソースコードの各テキスト行の先頭に置かれる。行番号を使用する言語では、連続で実行される文には行番号が増えるように行番号を与える必要がある。ただし、連続な番号である必要はない。例えば BASIC では次のようになっている。
10 X = 3 20 PRINT X
C言語やAdaといった言語のラベルは識別子であり、通常は行の先頭に書かれ、その直後にコロンが書かれる。例えば C では次のようになる。
Success: printf ("The operation was successful.\n");
Algol 60言語はラベルとして識別子も非負整数も使用可能(どちらもその後にコロンが続く)だが、多くのAlgol系言語では非負整数をラベルとして許容していない。
[編集] Goto
- 詳細はGoto文を参照。
goto 文は最も典型的な無条件の制御転送である。キーワードとしては大文字だったり小文字だったりする(言語に依存する)が、その形式は以下のようになっている。
goto label
goto 文は、次に実行する文をラベル(label)が示す箇所の直後の文とする。
goto 文は後述の if-then 文と組み合わせて条件付きの制御の転送を実現することが多い。言語によってはこの組み合わせの際に then または goto というキーワードを省略することがある。
IF condition THEN label IF (condition) GOTO label if condition then goto label; if (condition) goto label;
C言語などの多くの言語には似たような制御構文 break や continue がある。これらは機能が制限されているものの、つきつめれば無条件ジャンプである。しかし、これらのジャンプ先は使用される箇所によって自動的に決定されるので、ラベルを指定することはない。
[編集] サブルーチン
サブルーチンには、手続き、ルーチン、プロシージャ、関数(特に値を返す場合)、メソッドなど様々な名称がある。
1950年代、コンピュータのメモリは非常に小さかったため、サブルーチンの第一の目的はプログラムのサイズを削減することにあった。サブルーチンとして書かれたコードをプログラム内のあちこちから使用することでプログラム全体のコードサイズを削減したのである。現在ではサブルーチンはプログラムを構造化するために使われる。すなわち、特定のアルゴリズムを分離したり、特定のデータにアクセスするメソッドを隠蔽したりする。多数のプログラマが共同でプログラム開発をする場合、サブルーチンは仕事の分割点の役割も果たす。
サブルーチンに引数があればさらに便利になる。多くのプログラミング言語には平方根を求めるサブルーチンが組み込まれており、引数として平方根を求めたい数を与えることができる。
プログラミング言語によっては再帰呼び出しが可能である。つまり、サブルーチンが直接的あるいは間接的に自分自身を呼び出すことができる。クイックソートや木構造を探索するアルゴリズムなどは再帰を使った方が素直に表現できる。
サブルーチンを使用すると、引数の受け渡し、サブルーチン呼び出し、コールスタック処理、サブルーチンからの復帰などのオーバヘッドによりプログラム性能が若干低下する。実際のオーバヘッドはハードウェアおよびソフトウェアのアーキテクチャに依存する。コンパイラによってはインライン展開を効果的に使用してオーバヘッドの低減を図るものもある。
プログラミング言語によってはサブルーチンの物理的な最後尾に到達しないとサブルーチンから復帰できない方式のものもある。他の言語には return や exit 文がある。これはサブルーチンの最後尾への分岐と等価であり、制御構造を複雑化するものではない。必要に応じて複数のそれらの文をサブルーチン内に置くことができる。
多くの場合、サブルーチンの呼び出しは制御フローを一時的に変化させるだけである。ごく一部の言語には引数としてラベルを渡す機能があり、その場合の制御フローはかなり複雑化する。
以下の例は値を返すサブルーチンをBASICおよびPHP(C言語風の言語)で示している。
BASIC PHP BASIC 10 X = 2 | $x = 2; | 10 X = 2 20 Y = DOUBLE(X) | $y = double($x); | 18 FARG = X 30 PRINT Y | print $y; | 20 GOSUB 50 | | 22 Y = FRET FUNCTION DOUBLE(NUM) | function double($num) { | 30 PRINT Y NUM = NUM * 2 | $num *= 2; | 40 END RETURN NUM | return $num; | 50 FRET = FARG*2 | } | 60 RETURN
実行すると、プログラムは変数 X を定義し、その値を 2 とする。次の行でプログラムは DOUBLE というサブルーチンにジャンプし、X の値を一時変数 NUM にコピーする。その後サブルーチン内の命令を実行し(NUM に 2 をかける)、演算結果をメインプログラムの中のサブルーチンを呼び出した箇所に戻す。そこで変数 Y の値が設定され(4)、次の行でそれを表示する。プログラムはそこで停止し、その後にあるサブルーチン(FUNCTION)が実行されることはない。
[編集] 必要最小限の構造化制御フロー
1966年、Böhm と Jacopini は Communications of the ACM 誌で論文を発表し、goto を使って書かれたプログラムが選択(IF THEN ELSE)とループ(WHILE condition DO xxx)のみを使って goto を使わずに書き換えられることを示した(コードの一部を複製したり、真理値フラグ変数を追加する必要がある)。後に彼らは選択もループ(と追加の真理値変数)で置き換え可能であることを示した。
そのような書き換えが可能という事実は、必ずしもそれが望ましいということを意味したわけではなかった。コンピュータは一種類の命令(subtract one number from another and branch if the result is negative)さえあれば理論的には何でもできるが、実際のコンピュータは多数の命令を備えている。
Böhm と Jacopini の論文は全てのプログラムから goto 文を無くすことができることを示した。また、他の研究により入り口と出口がそれぞれひとつになっている制御構造が他の構造よりも理解し易いということが示された。特にそのような制御構造はプログラムの任意の箇所に制御構造を乱すことなく挿入可能な点が有利とされた。
[編集] 実際の制御構造
制御構造を持つ多くのプログラミング言語は制御構造の開始を指定するためのキーワードを持つ。制御構造の終了に対応するキーワードがあるかどうかで言語は分類できる。
- 終了キーワードがない言語:この種の言語は文の並びをひとまとめ(ブロック)にする何らかの方法を持っている。
- 終了キーワードがある言語:終了キーワードはいくつかの種類がある。
- Ada: 終了キーワードは end + 空白 + 開始キーワード。例えば、if ... end if, loop ... end loop
- Algol 68: 開始キーワードを逆に綴る。例えば、if ... fi, case ... esac
- Fortran 77: 終了キーワードは end + 開始キーワード。例えば、IF ... ENDIF, DO ... ENDDO
- Modula-2: 開始キーワードに関わらず常に end
- Visual Basic: 制御構造毎に固有の終了キーワード。If ... End If; For ... Next; Do ... Loop
終了キーワードを持つ言語はソースのレイアウトやインデントの仕方について議論されることが少ない傾向がある。また、その中でも終了キーワードが end + 開始キーワード となっているもの(空白を挟むか否かに関わらず)が学習が容易で読みやすいとされている。
[編集] 選択
[編集] 構造化 If
「構造化 if」は既述の「if」と異なり、複数の文にまたがって効力を持ち、Goto文を使わずに済む。
本節の例はAdaを使用している。
[編集] then 部
「構造化 If」の最も単純な形式では、条件が成り立つときのみ複数の文を実行する。
if condition then statements; ... end if;
[編集] else 部
else 部は条件が成り立たない場合に実行される文の並びを表している。
if condition then statements; ... else other statements; ... end if;
[編集] else-if 部
else-if を使うと、複数の条件を連結することができる。最初に成立する条件に対応する部分のみが実行され、他の文はスキップされる。最後の else はどの条件も成立しなかったときに実行される。
if condition then statements; ... elsif condition then more statements; ... elsif condition then more statements; ... ... else other statements; ... end if;
[編集] パターンマッチング
パターンマッチングとは、MLのような一部のプログラミング言語での高度に抽象化された if-then-else の名称である。ここではOCaml言語での例を挙げる。
match fruit with | "apple" -> cook pie | "coconut" -> cook dango_mochi | "banana" -> mix;;
[編集] 特定定数値に基づく選択
一般に case 文や switch 文として知られている。その機能は、指定された値を指定された定数群と比較し、最初に一致した定数に従ってその後の処理を決定するものである。定数群がコンパクトな範囲にあれば、これは整数値に基づく選択であるかのように非常に効率的に実装できる。一般にジャンプテーブルを使って実装されることが多い。
case someChar of switch (someChar) { 'a': actionOnA; case 'a': actionOnA; 'x': actionOnX; break; 'y','z':actionOnYandZ; case 'x': actionOnX; end; break; case 'y': case 'z': actionOnYandZ; break; default: actionOnNoMatch; }
言語やプログラミング環境によっては case や switch 文は、等価な if-else 文の集まりよりも読みやすく保守しやすいと言われている。C言語などでは、"switch" 文は選択されたコードから下をそのまま実行する(それを防ぐために break で switch 文から脱出する)。英語圏ではこの動作を "fall-through" と呼ぶ。
Duff's device は "switch"文の特徴を利用したループ展開技法である。
[編集] 1..N の数値に基づく選択
この制御構造を持つ言語は数少ないが、計算付きGOTOを使えば効率的に実装可能である。
GOTO (label1,label2,label3), I outOfRangeAction
case I in action1, action2, action3 out outOfRangeAction esac
つまり、I が 1 なら action1、2 なら action2、3 なら action3 を実行し、それら以外なら outOfRangeAction を実行する。
[編集] 算術 IF
FORTRAN 77には「算術IF」文があり、x < 0, x = 0, x > 0 という三分法に基づいた IF 文と CASE 文の中間のような働きをする。
IF (e) label1, label2, label3
ここで、e は何らかの数式(整数である必要はない)であり、この構文は以下と等価である。
IF (e < 0) GOTO label1 IF (e = 0) GOTO label2 IF (e > 0) GOTO label3
算術 IF は複数の GOTO 文と等価であるため、構造化されていない制御構文と見なされ、構造化された制御構文が使用可能であれば使うべきではない。実際、算術 IF 文が使われているソースを見てみると、ラベルを1つか2つしか指定していないことが多い。
このような特殊な構造が仕様として存在しているのは、本来の FORTRAN の実装(IBM 704)がこれを効率的に実装でき、3つの IF...GOTO を1つの命令で実現できたためである(Branch if accumulator negative)。
[編集] 選択構文の比較表
プログラミング言語 | 構造化 IF | 定数選択 | 数値選択 | 算術 IF | ||
---|---|---|---|---|---|---|
then | else | else-if | ||||
Ada | ○ | ○ | ○ | ○ | × | × |
C | ○ | ○ | × [1] | ○(次をそのまま実行) | × | × |
C++ | ○ | ○ | × [1] | ○(次をそのまま実行) | × | × |
FORTRAN | ○ | ○ | ○ | ○ | × | ○ |
PHP | ○ | ○ | ○ | ○(次をそのまま実行) | × | × |
[編集] ループ
ループはソースコード上1回書かれた文の並びを連続して複数回実行することである。ループの「中」のコード(本体と呼び、下記の例では xxx で表されている)は指定回数実行されるか、指定指されたコレクションの各要素に対応して実行されるか、何らかの条件が成立するまで繰り返し実行される。
Scheme言語のような言語では、ループは明確なループ用構文ではなく末尾再帰を使用して実現されることが多い。
[編集] カウント制御ループ
多くのプログラミング言語は指定された回数だけループを繰り返す構文を持っている。以下の例で N が 1 より小さい場合、ループ本体は全く実行されない。カウントは多くの場合増える方向だけでなく減る方向にも設定可能で、1回に増える量も 1 以外に設定できることが多い。
FOR I = 1 TO N for I := 1 to N do begin xxx xxx NEXT I end; DO I = 1,N for ( I=1; I<=N; ++I ) { xxx xxx END DO }
For文を参照されたい。
多くのプログラミング言語では、カウント制御ループでは整数のみが使われる。浮動小数点数はハードウェアの制限により精度に限界がある。従って次のようなループでは、
for X := 0.1 step 0.1 to 1.0 do
繰り返し回数が9回の場合と10回の場合がある。これは丸め誤差やハードウェアやコンパイラの違いによって変わってくる。
[編集] 条件制御ループ
また、多くのプログラミング言語は指定した条件が変化するまでループを繰り返す構文をもっている。条件のテストがループの先頭にある場合と最後にある場合がある。前者の場合、ループ本体を全く実行しないことがありうるが、後者の場合は少なくとも1回はループ本体を実行する。
DO WHILE (test) repeat xxx xxx END DO until test; while (test) { do xxx xxx } while (test);
While文を参照されたい。
[編集] コレクション制御ループ
一部のプログラミング言語(例えば、Smalltalk、Perl、Java言語、C#、Visual Basic)では、明示的に配列や集合やコレクションの全要素に対応してループを回すことができる。
someCollection do: [:eachElement |xxx]. foreach someArray { xxx } Collection<String> coll; for (String s : coll) {} foreach (string s in myStringCollection) { xxx }
[編集] 汎用繰り返し構文
C言語の for 文や Common Lisp の do のような汎用繰り返し構造を使えば、前述の各種ループもその他のループも実現できる。例えば、複数のコレクションを並列に回したりできる。もっと個別のループ構造がある場合、汎用繰り返し構文よりもそちらを使った方がコードの目的をより明確に表現できる。
[編集] 無限ループ
場合によっては無限にループする方がプログラムに適していることもあるし、何らかのエラーが発生するまでループするという場合もある。実際、イベント駆動型プログラムはイベント制御ループを永遠に回り続け、プロセスが操作者によって終了されられたときだけループを停止する。
ただし一般には、無限ループはプログラミングのミスで発生する。すなわち、ループ終了条件がループ内で全く発生しないことが原因で意図しない無限ループとなる。
[編集] 次の繰り返しへの継続
ループ途中でループ処理を中断してループの先頭に戻り、次の繰り返しを開始したい場合がある。言語によってはこれを実現する continue とか skip といった構文を用意している。その効果は最も内側のループ本体の実行を途中で止め、そのループの次の繰り返しを最初から行う。もしそのときの実行が最後の繰り返しであった場合、ループそのものを早期に終了させるのと同じことになる。
[編集] ループからの早期脱出
カウント制御型ループを使って配列上のデータを検索している際に、必要な要素を見つけたら即座にループから抜け出したいという状況がありうる。プログラミング言語によっては break とか exit といった文を用意していて、現在のループを即座に抜けてそのループの直後の文に制御を転送する機能を持っている。多次元配列を入れ子になったループで検索している場合、若干複雑になる(「提案された制御構造」の章参照)。
以下の例はAdaを使ったものである。Ada は「ループからの早期脱出」と「途中にテストのあるループ」の両方をサポートしている。どちらもよく似ているが、コードを比較すればその違いがわかる。「早期脱出」では if 文を使うのに対して、「途中のテスト」は独自の構文を使用する。
with Ada.Text_IO; with Ada.Integer_Text_IO; procedure Print_Squares is X : Integer; begin Read_Data : loop Ada.Integer_Text_IO.Get(X); if X = 0; then exit Read_Data; end if; Ada.Text_IO.Put(X * X); Ada.Text_IO.New_Line; end loop Read_Data; end Print_Squares;
Python はループを早期脱出したか否かに依存して実行するかどうかが決定される構文を用意している。以下はその例である。
for n in set_of_numbers: if isprime(n): print "Set contains a prime number" break else: print "Set did not contain any prime numbers"
Python では for 文も while 文もこのような else 節を使うことができる。else 節は早期脱出が発生しなかったときのみ実行される。
[編集] ループ機能の比較表
プログラミング言語 | 条件付き | ループ | 早期脱出 | 継続 | |||||
---|---|---|---|---|---|---|---|---|---|
先頭 | 途中 | 最後 | カウント | 集合型 | 汎用 | 無限 [2] | |||
Ada | ○ | ○ | ○ | ○ | 配列 | × | ○ | 深い入れ子 | × |
C | ○ | × | ○ | × [3] | × | ○ | × | 深い入れ子 [4] | ○ |
C++ | ○ | × | ○ | × [3] | × | ○ | × | 深い入れ子 [4] | ○ |
FORTRAN | ○ | × | × | ○ | × | × | ○ | 1レベル | ○ |
PHP | ○ | × | ○ | × [3] | ○ [5] | ○ | × | 深い入れ子 | ○ |
Python | ○ | × | × | × [6] | ○ | × | × | 深い入れ子 [7] | ○ |
[編集] 構造化非局所制御フロー
多くのプログラミング言語、特に動的なプログラミングスタイルを指向した言語では、「非局所制御フロー」の構造を持っている。これを使うと実行の流れは現在のコンテキストから離れ、事前に定義された場所から続行される。「例外」、「条件」、「継続」の3種類の典型的な非局所制御構造がある。
[編集] 条件
PL/I は標準で22種類の条件(ZERODIVIDE、SUBSCRIPTRANGE、ENDFILE など)をサポートし、これを発生(RAISE)させ、ON condition action; で解釈することができる。プログラマは独自の条件を定義することもできる。
構造無しの IF 文のように action にはひとつの文しか書けないので、多くの場合 GOTO 文を使って制御フローを継続する必要がある。
残念なことに、実装によってはこれは空間と時間を無視できないくらい浪費する(特に SUBSCRIPTRANGE の場合)。多くのプログラマは条件を使わないようコードを書くことが多かった。
典型的な文法例:
ON condition GOTO label
[編集] 例外
- 詳細は例外処理を参照。
最近の言語はGOTO文を使用せずに例外処理を行う構造化された制御構造を備えている。
try { xxx1 // この中のどこかで以下を使用する xxx2 // throw someValue; xxx3 } catch (someClass & someId) { // someClass の場合をキャッチ actionForSomeClass } catch (someType & anotherId) { // someType の場合をキャッチ actionForSomeType } catch (...) { // 既にキャッチされていない任意の値をキャッチ actionForAnythingElse }
任意の catch 節が上記の例では使用されている。D言語、Java言語、C#、Python では try 構造に finally 節を追加することができる。try 部分を離れる際にはどういう理由であっても必ず finally 節が実行されることが保証されている。これは処理を終了する際に何らかの高価な資源(オープン中のファイルやデータベース接続)を解放しなければならない場合に便利である。
FileStream stm = null; // C# の例 try { stm = new FileStream("logfile.txt", FileMode.Create); return ProcessStuff(stm); // 例外を発生する可能性がある } finally { if (stm != null) stm.Close(); }
この例は非常に一般的であり、C# ではこのための特別な構文がある。
using (FileStream stm = new FileStream("logfile.txt", FileMode.Create)) { return ProcessStuff(stm); // 例外を発生する可能性がある }
上記の例の usingブロックを離れるとき、コンパイラが自動的に stm オブジェクトを解放する。
このような言語はいずれも標準の例外を定義し、それらがどのような状況で発生するかを定義している。ユーザーは独自の例外を発生させることもできる(実際、C++ と Python は任意の型の throw と catch が可能)。
特定の throw にマッチする catch がない場合、マッチする catch が見つかるまで入れ子構造を遡り、サブルーチン呼び出しを遡る。メインプログラムまで遡っても対応する catch がない場合、プログラムは適切なエラーメッセージを出力して停止する。
AppleScript スクリプト言語 は "try" ブロックにいくつかの情報を提供する。
try set myNumber to myNumber / 0 on error e number n from f to t partial result pr if ( e = "Can't divide by zero" ) then display dialog "You idiot!" end try
[編集] 非局所制御フローの比較表
プログラミング言語 | 条件 | 例外 |
---|---|---|
Ada | × | ○ |
C | × | × |
C++ | × | ○ |
C# | × | ○ |
D | × | ○ |
Java | × | ○ |
Objective-C | × | ○ |
PHP | × | ○ |
PL/1 | ○ | × |
Python | × | ○ |
Ruby | × | ○ |
[編集] 提案された制御構造
Datamation 誌(1973年12月)に掲載されたふざけた記事で、R. Lawrence Clark は GOTO文を COMEFROM文で置き換えることを提案し、面白い例をいくつか提示した。これは実際に INTERCAL という言語で実装された。この言語はプログラムを可能な限り読みにくくするよう設計されている。
ドナルド・クヌースは1974年の論文 "Structured Programming with go to Statements" でこれまでの説明された制御構造でカバーされていない2種類の状況を提示し、それを実現する制御構造を例示した。有用性にも関わらず、これらの構文は主流のプログラミング言語に実装された例はない。
[編集] 途中にテストのあるループ
これは1972年にダールが提案した。
loop loop xxx1 read(char); while test; while not atEndOfFile; xxx2 write(char); repeat; repeat;
もし xxx1 が省略されたら、テストが先頭にあるループとなる。もし xxx2 が省略されたら、テストが最後尾にあるループとなる。while が省略されれば無限ループとなる。このように、このひとつの制御構文で多くのプログラミング言語にある複数の制御構文の代替となる。ありうべき派生としてループ内に複数の while テストを配置することを許すことが考えられるが、その場合は後述の exitwhen の方が適切である。
右の例では(ファイルを1文字ずつコピーする)、同じコードを繰り返したりテストを繰り返したりしないコードを作成するためにこの制御構造を使うのに適した最も単純な状況である。Ada言語では、上記のループ構造(loop-while-repeat)の代替として標準の無限ループ(loop-end loop)内で exit when節を使うことで同様の制御構造を実現できる(後述の exitwhen 文と混同しないよう注意されたい)。
with Ada.Text_IO; with Ada.Integer_Text_IO; procedure Print_Squares is X : Integer; begin Read_Data : loop Ada.Integer_Text_IO.Get(X); exit Read_Data when X = 0; Ada.Text_IO.Put(X * X); Ada.Text_IO.New_Line; end loop Read_Data; end Print_Squares;
ループの命名(この例では Read_Data)は必須ではないが、ループの入れ子で外側のループまで脱出させることができる。
[編集] 複数早期脱出と入れ子ループからの脱出
これは 1974年、Zahn が提案した。ここではそれを若干修正したものを示す。
exitwhen EventA or EventB or EventC; xxx exits EventA: actionA EventB: actionB EventC: actionC endexit;
exitwhen は xxx 内で発生しうるイベントを指定するのに使い、イベントはイベント名を文として使用すると発生する。イベントが発生すると対応するアクションが実行され、その後 endexit 後の処理に移る。この制御構造はある状況を識別する部分と、その状況でとるべきアクションを明確に区別することができる。
exitwhen は C++ 言語の try/catch 構造と概念的によく似ているが、サブルーチン呼び出しを超えたり任意の値を渡したりしないので、より効率的と思われる。また、コンパイラは指定されたイベントが全て発生する可能性があり、それらにアクションが対応しているかどうかをチェックできる。
以下の単純な例は2次元配列から特定の要素を取り出すものである。
exitwhen found or missing; for I := 1 to N do for J := 1 to M do if table[I,J] = target then found; missing; exits found: print("item is in table"); missing: print("item is not in table"); endexit;
[編集] 注
- ↑ 1.0 1.1 C/C++ でよく見かける
else if (condition)
は言語としての仕様ではなく、個別の if then else 文が入れ子になってあたかもひとつの構文であるかのようにコーディングされているだけのものである。しかし、これは else-if がコンパイル時に効率的に処理されるのでない限り C/C++ では必要とされないことを意味している。一般にelseif
は論理的にはif...else
の入れ子よりも単純であり、両方を用意している PHP などの言語ではelseif
はelse if
よりも効率的に処理される。 - ↑
while (true)
は言語としての構造ではないのでここでは無限ループに含めない。 - ↑ 3.0 3.1 3.2 C言語の
for (init; condition; loop)
ループは汎用ループ構造でありカウント専用ではない。ただし、一般にカウントループとして使われることが多い。 - ↑ 4.0 4.1 深いブレイクを C や C++ で実現するには、ラベルや Goto文を使う必要がある。
- ↑ オブジェクト群のイテレーションは PHP 5 で追加された。
- ↑ カウントループは例えば
range
やxrange
を使って incrementing list や generator でシミュレートされる。 - ↑ 深いブレイクを Python で実現するには、例外処理を活用する必要がある。
[編集] 関連項目
- Goto文
- サブルーチン
- メインループ
- 再帰呼び出し
- スパゲッティプログラム
- 構造化プログラミング
- 構造化プログラム理論
- 関数型プログラミング
[編集] 参考文献
- Dahl & Dijkstra & Hoare, "Structured Programming" Academic Press, 1972年
- Knuth, Donald E. "Structured Programming with go to Statements" ACM Computing Surveys 6(4):261-301, 1974年12月
- Böhm, Jacopini. Flow diagrams, "Turing Machines and Languages with only Two Formation Rules" Comm. ACM, 9(5):366-371, 1966年5月
- Hoare, C. A. R. "Partition: Algorithm 63," "Quicksort: Algorithm 64," and "Find: Algorithm 65." Comm. ACM 4, 321-322, 1961年
- Zahn, C. T. "A control statement for natural top-down structured programming" presented at Symposium on Programming Languages, Paris, 1974年