控制流程

控制流程或求值的順序。不論是在宣告式程式語言或是函式程式語言中，都有類似的概念。在宣告式的程式語言中，流程控制指令是指會改變程式執行順序的指令，可能是執行不同位置的指令，或是在二段程式中選擇一個執行。不同的程式語言所提供的流程控制指令也會隨之不同，但一般可以分為以下四種：中斷以及Unix系統中的訊號等較低階的機制也可以造成類似子程式的效果，不過通常這類機制會用來回應外部的事件或是輸入。程式自修改因為其對程式碼的影響，也會影響控制流程，但多半不會有明顯的流程控制指令。在機器語言或組合語言中，流程控制是藉由修改程式計數器數值來達到。一些中央處理器只支援條件分支。基本概念.標記.標記是一個標示在原始碼固定位置中的名稱或數字，其他位置的流程控制指令可以參考標記的位置，執行標記位置所對應的程式。標記本身不影響程式的進行，除了標示位置外，對程式執行沒有其他的作用。有一些程式語言利用行號作為標記。行號是標示在每一行程式最前面的自然數，不一定要是連續的數字，在不受流程控制指令影響的情形下，程式會從最小的行號依序執行，而流程控制指令需指定對應的行號。以下是一個BASIC的例子:10 LET X = 320 PRINT "*"30 LET X = X - 140 IF X &gt; 0 THEN GOTO 2050 END在像是C及Ada等程式語言中，標記是一個識別符號，一般出現在一行的最前面，後面會加一個冒號作為識別，以下是C語言的例子：Success: printf ("The operation was successful.\n");Algol 60語言同時支援整數，不過其他Algol語言幾乎都不支援整數的標記。Goto.goto 指令goto "label"goto 指令的效果是調整程式的控制流程，後續就執行標記位置的程式。goto 指令是許多的計算機科學家視為有害的指令，像荷蘭計算機科學家艾茲格·迪科斯徹就提出了goto有害論。子程式.子程式等。子程式是是完成一項特定工作的程式碼序列，其他程式可以將流程移轉到子程式中，執行特定工作後再回到原來的程式，若程式中有許多部份都需要執行一特定工作，利用子程式的方式可以利用一段程式達到上述的功能，可以減少程式碼的長度。如今子程式也常用來使得程式更加的結構化，例如可以將一些特殊的演演算法或特殊的資料存取方式放在子程式中，和其他程式碼隔離。子程式也是程式模組的一種，若許多程式設計師共同開發一個程式，子程式也有助於其工作的分割及分工。最簡結構化控制流程.1966年5月Corrado Böhm及Giuseppe Jacopini在《Communications of the ACM》期刊發表論文，說明任何一個有goto指令的程式，可以改為完全不使用goto指令的程式，goto指令可以用選擇指令取代，可能會再多一些重覆的程式碼及額外的布林變數。後來的研究者已證明選擇指令也可以用迴圈取代，不過需要更多的布林變數。Böhm及Jacopini的論文說明程式可以完全不使用goto，但是在實務上大家不一定會想要這麼進行。其他的研究說明若控制結構只有一個進入點。常用的控制結構.若一程式語言支援控制結構，控制結構開始時多半都會有特定的關鍵字，以標明是使用哪一種控制結構。但只有部份程式語言在控制結構結束時會有特定的關鍵字表示結束，因此可以依控制結構結束時是否有特定關鍵字來將程式語言分為二類。條件判斷.條件判斷是依指定變數或運算式的結果，決定後續執行的程式，最常用的是if-else指令，可以根據指定條件是否成立，決定後續的程式。也可以組合多個if-else指令，進行較複雜的條件判斷。許多程式語言也提供多選一的條件判斷，例如C語言的switch-case指令。迴圈.迴圈是指一段在程式中只出現一次，但可能會連續執行多次的程式碼。常見的迴圈可以分為二種，指定執行次數的迴圈。在一些函式程式語言中會使用遞迴或不動點組合子來達到迴圈的效果，其中尾部遞迴是一種特別的遞迴，很容易轉換為迭代。結構化的非區部控制流程.有些程式語言會提供非區部的控制流程三種。條件處理.PL/I程式語言中有22種標準的條件，可以在程式中設定，當特定條件成立時需進行的指令，程式設計者也可以定義自己的條件，並在程式中使用。條件成立時，只能設定一個需進行的指令，大部份的應用中，都會指定執行goto指令，跳到其他程式碼執行對應的流程。不過因為有些條件處理的實現會增加許多程式碼及執行時間，所以許多程式設計者會儘量不使用條件處理。條件處理的語法如下:ON "條件" GOTO "label"異常處理.有些程式語言可提供不需要使用codice_28的結構化異常處理程式：try {xxx1 // Somewhere in herexxx2 // use: throw someValue;xxx3} catch (someClass&amp; someId) { // catch value of someClassactionForSomeClass} catch (someType&amp; anotherId) { // catch value of someTypeactionForSomeType} catch (...) { // catch anything not already caughtactionForAnythingElse在codice_29的區塊中，若有異常情形時，程式就會離開try的區塊，由後續的一個或多個codice_30子句判斷需執行何種異常處理。在D、Java、C#及Python程式語言中，codice_29區塊中還可以加入一個codice_32子句，不管程式流程是否離開codice_29區塊，codice_32子句中的程式都一定會執行，常用在當程式結束處理時，需要放棄一些外部資源的情形下：FileStream stm = null; // C# exampletry {stm = new FileStream ("logfile.txt", FileMode.Create);return ProcessStuff(stm); // may throw an exception} finally {if (stm != null)stm. Close();由於上述情形相當普遍，C#提供一種特殊的語法進行相同的處理：using (FileStream stm = new FileStream ("logfile.txt", FileMode.Create)) {return ProcessStuff(stm); // may throw an exception只要離開 codice_35區塊，編譯器會自動釋放codice_36物件，Python的 codice_37指令及也有類似的功能。這些語言都有定義標準的異常情形及其出現的條件，程式設計者也可以丟出自己產生的異常。若某一個codice_38指令找不到對應的codice_30，控制流程會離開目前的副程式或控制結構，設法找到對應的codice_30，若到主程式的結尾還是找不到對應的codice_30，程式會強制結束，並顯示適當的錯誤訊息。AppleScript指令碼語言可以將"codice_42"區塊分為幾個部份，提供不同的訊息及異常：tryset myNumber to myNumber / 0on error e number n from f to t partial result prif ( e = "Can't divide by zero" ) then display dialog "You idiot!"end try續體.續體儲存成一個物件，後續在其他子程式中可以利用此物件回到此子程式現在的執行狀態。續體一詞也可以指第一類續體，是指程式語言可以在任意時間點儲存目前的執行狀態，並在之後回到之前儲存的執行狀態。程式需要分配空間給子程式用到的區域變數，而且在子程式結束時需釋出這些變數用到的空間。許多程式語言利用呼叫堆疊來存放這些變數，可以簡單快速的分配及釋出空間。也有一些程式語言使用動態記憶體分配來儲存變數，可以較靈活的分配變數，但分配及釋出空間較不方便。這二個架構下續體的處理方式也會不同，各有其優點及缺點。Scheme語言利用codice_43函式 可提供續體功能。