Control flow Niet te verwarren met Flow control.
Control flow of besturingsstroom is een begrip uit de informatica. Het slaat op de (niet-lineaire) volgorde van uitvoering van de instructies in een computerprogramma. Control flow wordt meestal bepaald door het gebruik van besturingsstructuren zoals lussen (while, for), beslissingsstructuren (if, case), spronginstructies en het aanroepen van subprogrammas. Labels en gotoDe meest elementaire vorm van een besturingsstroom is het gebruik van goto in combinatie met een if-opdracht. Hierbij wordt meestal een label gebruikt om aan te geven waarheen gesprongen moet worden. Hoewel op deze manier alle verderop genoemde vormen van control flow kunnen worden verwezenlijkt, wordt deze in de meeste programmeertalen niet gebruikt, of wordt het gebruik ontraden, vanwege de slechte programmastructuur die dit oplevert. BesturingsstructurenAlle programmeertalen behalve smaltalk kennen besturingsstructuren. Hierbij wordt een blok van statements (uitvoeringsblok ) gecontroleerd door een simpele structuur die voor of om dit uitvoeringsblok is geplaatst. Deze controle houdt in dat gestuurd wordt of, en zo ja hoe vaak het uitvoeringsblok wordt uitgevoerd. Een besturingsstructuur wordt altijd begonnen met een sleutelwoord, meestal gevolgd door een besturingsuitdrukking (expressie). Voorbeelden van deze sleutelwoorden zijn: for, while, if, switch en case Hoe het einde van het uitvoeringsblok wordt aangegeven is verschillend voor verschillende talen.
In principe zijn alle besturingsstructuren onder te verdelen in:
KeuzestructurenTestDeze structuur vindt men in alle programmeertalen. Afhankelijk van de conditie wordt het uitvoeringsblok uitgevoerd. Vaak ziet deze er als volgt uit: if (conditie) { ... } In andere talen, onder andere Basic, ziet het er zo uit: if conditie then ... end if Verder is er vaak een alternatief uitvoeringsblok voor wanneer niet aan de conditie wordt voldaan: if (conditie) { ... } else { ... } In Basic kennen we deze notatie ook, maar in heel oude versies wordt echter het alternatieve uitvoeringsblok niet ondersteund. BASIC versie 7.0 van de Commodore 128 kent die notatie alleen met een BEGIN...BEND zoals hieronder is te zien: IF conditie THEN BEGIN ... BEND:ELSE BEGIN ... BEND Ook zien we vaak dat ook nog op een tweede (en volgende ) conditie getest kan worden, met bijbehorende uitvoeringsblokken: if (conditie1) { ... } elseif (conditie2) { ... } else { ... } Ook Basic kent deze structuur zoals Visual Basic, maar oudere versies en BASIC 7.0 ondersteunen deze niet. KeuzeIn veel talen is het ook mogelijk om op basis van 1 getal een van de vele uitvoeringsblokken te selecteren: switch (waarde) { case 1: // uitvoeringsblok 1 ... case 2: // uitvoeringsblok 2 ... case 3: // uitvoeringsblok 3 ... case 4: // uitvoeringsblok 4 ... case 5: // uitvoeringsblok 5 ... default: } In verschillende Basic dialecten werkt het zo: select case waarde case 1 ' uitvoeringsblok 1 ... case 2 ' uitvoeringsblok 2 ... case 3 ' uitvoeringsblok 3 ... case 4 ' uitvoeringsblok 4 ... case 5 ' uitvoeringsblok 5 ... case else ... end select LussenIn een lus wordt een uitvoeringsblok meermalen doorlopen. Iedere keer dat deze doorlopen wordt, wordt een iteratie genoemd. De belangrijkste lussen worden hieronder genoemd. Conditiegestuurde lussenBij deze vorm van een lus wordt, zolang er aan een voorwaarde wordt voldaan, het uitvoeringsblok uitgevoerd. We komen dit tegen in de meeste moderne programmeertalen (in ieder geval in C, C++ C#, java, javascript, pascal ook in latere dialecten van algol) in de vorm: while (conditie) { ... } en do { ... } while (conditie); Ook Basic kent deze voorwaardelijke lussen hetgeen weer de accolades verdwijnen. Een while loop moet echter eindigen met een wend en in Visual Basic .NET zelfs met end while. Bij de laatste voorwaardelijke lus wordt het uitvoeringsblok altijd in ieder geval 1 keer doorlopen. Bij oudere talen kom je ook tegen: repeat ... until conditie Tellergestuurde lussenDeze lussen zijn bedoeld om het uitvoeringsblok een vooraf ingesteld aantal keren te doorlopen. Alle programmeertalen van de laatste 25 jaar kennen een dergelijke constructie, en zelfs een aantal assemblers (bv de 80386 assembler en hoger) hebben een dergelijke lus standaard ingebouwd. Binnen de lus kan de teller nog gebruikt worden in de statements. In C, C++, C#, Java en Javascript kan een tellergestuurde lus er zo uitzien: for (i = 0; i < einde; i++) { ... } In Basic zo: For i = 1 To einde Step 1 ... Next i Verzamelinggestuurde lussenDeze lussen zijn bedoeld om het uitvoeringsblok voor ieder element (van een bepaald type) van een verzameling te doorlopen. We komen deze constructie tegen in C#, Visual Basic, Visual Basic .NET, javascript, Smaltalk en Perl. In C# kan zoiets er zo uitzien: foreach (Kat k in MijnDierenVerzameling) { ... } In Visual Basic en Visual Basic .NET zal hetzelfde er als volgt uitzien. Dim K As Kat For Each K In MijnDierenVerzameling ... Next K Let er op dat MijnDierenVerzameling ook honden kan bevatten, maar deze worden niet aan het uitvoeringsblok aangeboden. Bijzondere mogelijkheden binnen een lusOver het algemeen voorziet een programmeertaal in mogelijkheden om een loop voortijdig af te breken. Hiermee wordt dan de voorwaarde die in de besturingsuitdrukking zit gepasseerd. In veel talen kan dit met het break statement. Javascript heeft hierbij als enige taal de mogelijkheid om aan break een label mee te geven, zodat in één keer meer geneste lussen verlaten kunnen worden In basic wordt hiervoor Exit gevolgd door de loop soort gebruikt (bv Exit For). Ook is het vaak mogelijk om voor deze keer de rest van het uitvoeringsblok over te slaan, en gelijk door te gaan met de volgende iteratie. Hiervoor wordt vaak het continue-statement gebruikt. Recursie als alternatief voor een lusAls een functie zichzelf herhaaldelijk aanroept, wordt dit recursie genoemd. Op deze manier zijn veel zaken die met een lus mogelijk zijn ook te verwerkelijken. Dat kan ook in Basic worden gebruikt. Voorbeeld: De som van alle getallen tot getal 1 + 2 + .... + getal Voorbeeld van een recursieve functie, en een loop die hetzelfde doet int TelOpTot(int getal) { if (getal > 0) { return (getal + TelOpTot(getal - 1)); } return 0; } int TelOpTot(int getal) { int resultaat = 0 while (getal > 0) { resultaat += getal; getal--; } return 0; } Oneindige lussen Zie Oneindige lus voor het hoofdartikel over dit onderwerp.
Sommige lussen worden (onbedoeld) oneindig uitgevoerd. Dit soort lussen kunnen ontstaan door het ontbreken van een voorwaarde om de lus te beëindigen of een voorwaarde waar nooit aan voldaan wordt (of kan worden). Een recursie die niet termineert kan ook een reden zijn waarom een oneindige lus ontstaat. Dode code Zie Dode code voor het hoofdartikel over dit onderwerp.
Het is mogelijk dat bepaalde stukken code nooit uitgevoerd kunnen worden. Deze stukken code worden dode code genoemd. Een compiler kan de besturingsstroom van een programma analyseren om de dode code op te sporen. TriviaBij een van de eerste assembleertalen werd de besturingsstroom uitsluitend gedaan door middel van een speciale testinstructie. Afhankelijk van het resultaat van deze test instructie werd de volgende instructie overgeslagen of uitgevoerd. Gebruikelijk was om dan de volgende opdracht een sprongopdracht te laten zijn. |