Řízení toku - Control flow

Ve vědě o počítačích , řídící tok (nebo proud kontroly ) je pořadí, ve kterém jednotlivé příkazy , pokyny nebo volání funkce po dosažení imperativní programu jsou prováděny nebo vyhodnocovány. Důraz na explicitní tok řízení odlišuje imperativní programovací jazyk od deklarativního programovacího jazyka.

V rámci imperativního programovacího jazyka je příkaz toku řízení příkazem, jehož výsledkem je volba, kterou ze dvou nebo více cest následovat. U nekompaktních funkčních jazyků existují funkce a jazykové konstrukce , aby se dosáhlo stejného výsledku, ale obvykle se nenazývají příkazy toku řízení.

Sada příkazů je zase obecně strukturována jako blok , který kromě seskupování definuje také lexikální rozsah .

Přerušení a signály jsou mechanismy nízké úrovně, které mohou změnit tok řízení podobným způsobem jako podprogram , ale obvykle se vyskytují jako reakce na nějaký vnější podnět nebo událost (která může nastat asynchronně ), spíše než provádění in-line prohlášení o řízení toku.

Na úrovni strojového jazyka nebo jazyka sestavení pokyny toku řízení obvykle fungují změnou čítače programu . U některých centrálních procesorových jednotek (CPU) jsou jediným dostupným příkazem řídicího toku podmíněné nebo nepodmíněné větvící pokyny, označované také jako skoky.

Kategorie

Vývojový diagram řízení toku představení.

Druhy příkazů toku řízení podporovaných různými jazyky se liší, ale lze je kategorizovat podle jejich účinku:

  • Pokračování v jiném prohlášení (bezpodmínečná větev nebo skok)
  • Provedení sady příkazů pouze v případě, že je splněna nějaká podmínka (volba - tj. Podmíněná větev )
  • Provedení sady příkazů nula nebo vícekrát, dokud není splněna nějaká podmínka (tj. Smyčka - stejná jako podmíněná větev )
  • Provedení sady vzdálených příkazů, po kterých se tok řízení obvykle vrací ( podprogramy , korutiny a pokračování )
  • Zastavení programu, zabránění dalšímu provádění (bezpodmínečné zastavení)

Primitivů

Štítky

Štítek je explicitní jméno nebo číslo přiřazené pevné poloze uvnitř zdrojového kódu , a který může být odkazuje prohlášení řízení toku se objevují na jiném místě ve zdrojovém kódu. Štítek označuje pozici ve zdrojovém kódu a nemá žádný jiný účinek.

Čísla řádků jsou alternativou k pojmenovanému štítku používanému v některých jazycích (například BASIC ). Jsou to celá čísla umístěná na začátku každého řádku textu ve zdrojovém kódu. Jazyky, které je používají, často kladou omezení, že čísla řádků musí nabývat na hodnotě v každém následujícím řádku, ale nemusí vyžadovat, aby byla po sobě jdoucí. Například v ZÁKLADĚ:

10 LET X = 3
20 PRINT X

V jiných jazycích, jako je C a Ada , je štítek identifikátorem , obvykle se objevuje na začátku řádku a bezprostředně za ním je dvojtečka. Například v C:

Success: printf("The operation was successful.\n");

Jazyk ALGOL 60 povolil jako popisky celá čísla i identifikátory (oba spojené dvojtečkami s následujícím příkazem), ale jen málo, pokud nějaké jiné varianty ALGOL, umožňovaly celá čísla. Starší kompilátoři Fortranu povolovali pouze celá čísla jako štítky. Počínaje Fortranem-90 byly povoleny také alfanumerické štítky.

Jít do

Prohlášení goto (kombinace anglických slov go a to a podle toho se vyslovuje) je nejzákladnější formou bezpodmínečného přenosu kontroly.

Ačkoli klíčové slovo může být buď velké nebo malé v závislosti na jazyce, obvykle je napsáno jako:

   goto label

Účinek příkazu goto způsobí, že dalším provedeným příkazem bude příkaz, který se objeví na (nebo bezprostředně po) uvedeném štítku.

Mnoho počítačových vědců, zejména Dijkstra, považovalo prohlášení Goto za škodlivé .

Podprogramy

Terminologie podprogramů se liší; mohou být alternativně známé jako rutiny, postupy, funkce (zejména pokud vracejí výsledky) nebo metody (zejména pokud patří do tříd nebo tříd typů ).

V padesátých letech byly počítačové paměti podle současných standardů velmi malé, takže podprogramy byly používány hlavně ke zmenšení velikosti programu. Část kódu byla napsána jednou a poté mnohokrát použita z různých jiných míst v programu.

Dnes se častěji používají podprogramy, které pomáhají vytvořit program strukturovanější, například izolací nějakého algoritmu nebo skrytím některé metody přístupu k datům. Pokud na jednom programu pracuje mnoho programátorů, podprogramy jsou jeden druh modularity, který může pomoci rozdělit práci.

Sekvence

Ve strukturovaném programování je uspořádané sekvenování po sobě jdoucích příkazů považováno za jednu ze základních řídicích struktur, která se používá jako stavební blok programů vedle iterace, rekurze a volby.

Minimální strukturovaný řídicí tok

V květnu 1966 publikovali Böhm a Jacopini v Komunikaci ACM článek, který ukázal, že jakýkoli program s goto s lze transformovat do bezobslužné formy zahrnující pouze volbu (IF THEN ELSE) a smyčky (WHILE podmínka DO xxx), event. s duplikovaným kódem a/nebo přidáním booleovských proměnných (true/false příznaky). Pozdější autoři ukázali, že volbu lze nahradit smyčkami (a ještě dalšími booleovskými proměnnými).

Že je takový minimalismus možný, neznamená, že je nezbytně žádoucí; koneckonců počítače teoreticky potřebují pouze jednu strojovou instrukci (odečte jedno číslo od druhého a větví, pokud je výsledek negativní), ale praktické počítače mají desítky nebo dokonce stovky strojních instrukcí.

Článek Böhma a Jacopiniho ukázal, že všechny programy mohou být bez přechodů. Jiný výzkum ukázal, že řídicí struktury s jedním vstupem a jedním výstupem byly mnohem snáze pochopitelné než jakákoli jiná forma, hlavně proto, že je bylo možné použít kdekoli jako příkaz bez narušení toku řízení. Jinými slovy, byly složitelné . (V této strategii pokračovaly pozdější vývojy, například nepříliš přísné programovací jazyky -a v poslední době také transakce se skládatelným softwarem -a ještě více se tak skládaly součásti programů.)

Někteří akademici zaujali puristický přístup k výsledku Böhm-Jacopini a tvrdili, že i instrukce jako breaka returnze středu smyček jsou špatnou praxí, protože v Böhm-Jacopiniho důkazu nejsou potřeba, a proto prosazovali, aby všechny smyčky měly jeden výstupní bod. Tento puristický přístup je ztělesněn v jazyce Pascal (navrženém v letech 1968–1969), který byl až do poloviny 90. let preferovaným nástrojem pro výuku úvodního programování na akademické půdě. Přímá aplikace Böhm-Jacopiniho věty může mít za následek, že do strukturovaného grafu budou zavedeny další lokální proměnné, a také může dojít k určité duplikaci kódu . Pascal je ovlivněn oběma těmito problémy a podle empirických studií citovaných Ericem S. Robertsem měli studentští programátoři potíže s formulací správných řešení v Pascalu pro několik jednoduchých problémů, včetně psaní funkce pro vyhledávání prvku v poli. Studie Henryho Shapira z roku 1980 citovaná Robertsem zjistila, že s použitím pouze řídicích struktur poskytnutých Pascalem poskytlo správné řešení pouze 20% subjektů, zatímco žádný subjekt pro tento problém nenapsal nesprávný kód, pokud mu bylo dovoleno napsat návrat z uprostřed smyčky.

Řídicí struktury v praxi

Většina programovacích jazyků s řídicími strukturami má počáteční klíčové slovo, které označuje typ zapojené řídicí struktury. Jazyky se poté rozdělí, zda mají řídicí struktury konečné klíčové slovo.

  • Žádné konečné klíčové slovo: ALGOL 60 , C , C ++ , Haskell , Java , Pascal , Perl , PHP , PL/I , Python , PowerShell . Takové jazyky potřebují nějaký způsob seskupování příkazů dohromady:
    • ALGOL 60 a Pascal: begin...end
    • C, C ++, Java, Perl, PHP a PowerShell: složené závorky { ...}
    • PL/I: DO...END
    • Python: používá úroveň odsazení (viz pravidlo mimo stranu )
    • Haskell: Lze použít buď úroveň odsazení, nebo složené závorky a lze je libovolně míchat
    • Lua: používá do...end
  • Konečné klíčové slovo: Ada , ALGOL 68 , Modula-2 , Fortran 77 , Mythryl , Visual Basic . Formy konečného klíčového slova se liší:
    • Ada: konečné klíčové slovo je end+ mezera + počáteční klíčové slovo např. if... end if, loop...end loop
    • ALGOL 68, Mythryl: počáteční klíčové slovo napsané pozpátku, např. if... fi, case...esac
    • Fortran 77: konečné klíčové slovo je END+ počáteční klíčové slovo např. IF... ENDIF, DO...ENDDO
    • Modula-2: stejné konečné klíčové slovo ENDpro všechno
    • Visual Basic: každá řídicí struktura má své vlastní klíčové slovo. If... End If; For... Next; Do... Loop; While...Wend

Výběr

If-then- (else) prohlášení

Podmíněné výrazy a podmíněné konstrukce jsou rysy programovacího jazyka, které provádějí různé výpočty nebo akce v závislosti na tom, zda logická podmínka specifikovaná programátorem vyhodnotí jako true nebo false.

  • IF..GOTO. Formulář nalezený v nestrukturovaných jazycích, napodobující typickou instrukci strojového kódu, by po splnění podmínky přeskočil na (GOTO) číslo štítku nebo řádku.
  • IF..THEN..(ENDIF). Jakékoli jednoduché prohlášení nebo vnořený blok by se nemělo omezovat na skok, ale za klíčovým klíčovým slovem THEN. Toto je strukturovaná forma.
  • IF..THEN..ELSE..(ENDIF). Jak je uvedeno výše, ale s druhou akcí, která má být provedena, pokud je podmínka nepravdivá. Jedná se o jednu z nejběžnějších forem s mnoha variacemi. Některé vyžadují terminál ENDIF, jiné ne. C a související jazyky nevyžadují klíčové slovo terminálu nebo „pak“, ale vyžadují podmínku v závorkách.
  • Podmíněné příkazy mohou být a často jsou vnořeny uvnitř jiných podmíněných příkazů. Některé jazyky umožňují ELSEa IFlze je kombinovat ELSEIF, takže není nutné mít ENDIFna konci složeného příkazu řadu nebo jiná závěrečná prohlášení.
Pascal : Ada : C : Skript prostředí : Python : Lisp :
if a > 0 then
  writeln("yes")
else
  writeln("no");
if a > 0 then
      Put_Line("yes");
else
      Put_Line("no");
end if;
if (a > 0) { 
    printf("yes");
}
else {
    printf("no");
}
if [ $a -gt 0 ]; then
      echo "yes"
else
      echo "no"
fi
if a > 0: 
    print("yes")
else:
    print("no")
(princ
  (if (plusp a)
      "yes"
      "no"))

Mezi méně obvyklé varianty patří:

  • Některé jazyky, například Fortran , mají třícestný nebo aritmetický test, pokud testují, zda je číselná hodnota kladná, záporná nebo nulová.
  • Některé jazyky mají funkční formu ifprohlášení, například Lisp cond .
  • Některé jazyky mají operátor formu ifprohlášení, jako například C je ternární operátor .
  • Perl doplňuje styl C ifpomocí whena unless.
  • Smalltalk používá ifTruea ifFalsezprávy k implementaci podmíněných, nikoli jakýchkoli základních jazykových konstrukcí.

Případy a přepínače

Přepněte příkazy (nebo příkazy případu nebo vícecestné větve ) porovnejte danou hodnotu se zadanými konstantami a proveďte akci podle první konstanty, která se má shodovat. Pokud žádná shoda neuspěje, obvykle existuje ustanovení o provedení výchozí akce („else“, „jinak“). Příkazy přepínače mohou povolit optimalizace kompilátoru, například vyhledávací tabulky . V dynamických jazycích nemusí být případy omezeny na konstantní výrazy a mohou se rozšířit na párování vzorů , jako v příkladu skriptu prostředí vpravo, kde *)implementuje výchozí případ jako glob odpovídající libovolnému řetězci. Case Logic může být také realizována ve funkční podobě, jako v SQL je decodeprohlášení.

Pascal : Ada : C : Skript prostředí : Lisp :
case someChar of
  'a': actionOnA;
  'x': actionOnX;
  'y','z':actionOnYandZ;
  else actionOnNoMatch;
end;
case someChar is
  when 'a' => actionOnA;
  when 'x' => actionOnX;
  when 'y' | 'z' => actionOnYandZ;
  when others => actionOnNoMatch;
end;
switch (someChar) {
  case 'a': actionOnA; break;
  case 'x': actionOnX; break;
  case 'y':
  case 'z': actionOnYandZ; break;
  default: actionOnNoMatch;
}
case $someChar in 
   a)    actionOnA ;;
   x)    actionOnX ;;
   [yz]) actionOnYandZ ;;
   *)    actionOnNoMatch  ;;
esac
(case some-char
  ((#\a)     action-on-a)
  ((#\x)     action-on-x)
  ((#\y #\z) action-on-y-and-z)
  (else      action-on-no-match))

Smyčky

Smyčka je posloupnost příkazů, která je zadána jednou, ale která může být provedena několikrát za sebou. Kód „uvnitř“ smyčky ( tělo smyčky, zobrazený níže jako xxx ) je dodržován stanovený počet opakování nebo jednou pro každou kolekci položek, nebo dokud není splněna nějaká podmínka, nebo na neurčito .

Ve funkčních programovacích jazycích, jako je Haskell a Scheme , lze smyčky vyjádřit pomocí rekurze nebo iterace s pevným bodem, nikoli pomocí explicitních smyčkových konstrukcí. Rekurze ocasu je speciální případ rekurze, který lze snadno transformovat na iteraci.

Počet smyček

Většina programovacích jazyků má konstrukce pro opakování smyčky několikrát. Ve většině případů může počítání jít dolů namísto nahoru a lze použít i jiné velikosti kroků než 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                   | }

V těchto příkladech platí, že pokud N <1, pak se tělo smyčky může spustit jednou (přičemž I má hodnotu 1) nebo vůbec, v závislosti na programovacím jazyce.

V mnoha programovacích jazycích lze ve smyčce řízené počtem spolehlivě použít pouze celá čísla. Čísla s plovoucí desetinnou čárkou jsou reprezentována nepřesně kvůli hardwarovým omezením, takže smyčka jako

   for X := 0.1 step 0.1 to 1.0 do

se může opakovat 9 nebo 10krát, v závislosti na zaokrouhlovacích chybách a/nebo verzi hardwaru a/nebo kompilátoru. Kromě toho, pokud k přírůstku X dochází opakovaným přidáváním, nahromaděné chyby zaokrouhlování mohou znamenat, že hodnota X v každé iteraci se může poměrně výrazně lišit od očekávané sekvence 0,1, 0,2, 0,3, ..., 1,0.

Smyčky řízené podmínkou

Většina programovacích jazyků má konstrukce pro opakování smyčky, dokud se nezmění některé podmínky. Některé varianty testují stav na začátku smyčky; ostatní to testují na konci. Pokud je test na začátku, tělo může být zcela vynecháno; pokud je na konci, tělo je vždy provedeno alespoň jednou.

   DO WHILE (test)          | repeat 
       xxx                  |     xxx 
   LOOP                     | until test;
----------------------------------------------
   while (test) {           | do
       xxx                  |     xxx
   }                        | while (test);

Kontrola zlomu je metoda detekce změna hodnoty použity v rámci běžných smyčky zpracování spouštěcí pro skupiny hodnot. Hodnoty jsou monitorovány ve smyčce a změna přesměruje tok programu na zpracování skupinové události s nimi spojené.

   DO UNTIL (End-of-File)
      IF new-zipcode <> current-zipcode
         display_tally(current-zipcode, zipcount)
         
         current-zipcode = new-zipcode
         zipcount = 0
      ENDIF
      
      zipcount++
   LOOP

Smyčky řízené sběrem

Několik programovacích jazyků (např. Ada , D , C ++ 11 , Smalltalk , PHP , Perl , Object Pascal , Java , C# , MATLAB , Visual Basic , Ruby , Python , JavaScript , Fortran 95 a novější) má speciální konstrukce, které umožňují implicitní procházející všemi prvky pole nebo všemi členy sady nebo kolekce.

   someCollection do: [:eachElement |xxx].
   for Item in Collection do begin xxx end;

   foreach (item; myCollection) { xxx }

   foreach someArray { xxx }

   foreach ($someArray as $k => $v) { xxx }

   Collection<String> coll; for (String s : coll) {}

   foreach (string s in myStringCollection) { xxx }

   someCollection | ForEach-Object { $_ }
   forall ( index = first:last:step... )

Scalavýrazy for-expressions , které generalizují smyčky řízené kolekcí, a také podporují další použití, například asynchronní programování . Haskell má výrazy a porozumění, které dohromady poskytují podobnou funkci jako výrazy ve Scale.

Obecná iterace

Obecně iterace konstrukty jako například C v forprohlášení a Common Lisp je doforma může být použita k vyjádření některého z výše uvedených druhů smyček, a jiní, jako je vytváření smyček přes určitý počet kolekcí paralelně. Tam, kde lze použít specifičtější smyčkovou konstrukci, je obvykle upřednostňována před obecnou iterační konstrukcí, protože často činí účel výrazu jasnějším.

Nekonečné smyčky

Nekonečné smyčky se používají k zajištění smyček programových segmentů navždy nebo dokud nenastanou výjimečné podmínky, jako je chyba. Například program řízený událostmi (jako je server ) by se měl navždy opakovat a zpracovávat události tak, jak nastanou, pouze se zastaví, když je proces ukončen operátorem.

Nekonečné smyčky lze implementovat pomocí jiných konstrukcí toku řízení. Nejčastěji je to u nestrukturovaného programování skok zpět (goto), zatímco u strukturovaného programování jde o neurčitou smyčku (while loop) nastavenou tak, aby nikdy nekončila, a to buď vynecháním podmínky, nebo explicitním nastavením na true, jako while (true) .... Některé jazyky mají speciální konstrukce pro nekonečné smyčky, obvykle vynecháním podmínky z neurčité smyčky. Mezi příklady patří Ada ( loop ... end loop), Fortran ( DO ... END DO), Go ( for { ... }) a Ruby ( loop do ... end).

Nekonečná smyčka je často neúmyslně vytvořena chybou programování ve smyčce řízené podmínkami, přičemž podmínka smyčky používá proměnné, které se ve smyčce nikdy nemění.

Pokračování další iterací

Někdy v těle smyčky existuje touha přeskočit zbytek těla smyčky a pokračovat v další iteraci smyčky. Některé jazyky poskytují prohlášení jako continue(většina jazyků), skipnebo next(Perl a Ruby), které to udělají. Účinkem je předčasné ukončení nejvnitřnějšího těla smyčky a následné pokračování jako obvykle s další iterací. Pokud je iterace poslední ve smyčce, výsledkem je předčasné ukončení celé smyčky.

Znovu provést aktuální iteraci

Některé jazyky, jako Perl a Ruby, mají redopříkaz, který restartuje aktuální iteraci od začátku.

Restartujte smyčku

Ruby má retrypříkaz, který restartuje celou smyčku od počáteční iterace.

Předčasný odchod ze smyček

Při použití smyčky řízené počtem k vyhledávání v tabulce může být žádoucí zastavit vyhledávání, jakmile je nalezena požadovaná položka. Některé programovací jazyky poskytují příkazy jako break(většina jazyků), Exit(Visual Basic) nebo last(Perl), což má za následek okamžité ukončení aktuální smyčky a přenos řízení do příkazu bezprostředně po této smyčce. Dalším termínem pro smyčky s předčasným ukončením je smyčka a půl .

Následující příklad je proveden v Ada, která podporuje jak předčasné ukončení smyček, tak smyčky s testem uprostřed . Obě funkce jsou velmi podobné a porovnání obou úryvků kódu ukáže rozdíl: early exit musí být kombinován s příkazem if, zatímco podmínka uprostřed je samostatná konstrukce.

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;

Python podporuje podmíněné spouštění kódu v závislosti na tom, zda byla smyčka ukončena předčasně (s breakpříkazem) nebo ne pomocí klauzule else se smyčkou. Například,

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")

elseKlauzule ve výše uvedeném příkladu je spojeno s forprohlášením, a nikoli vnitřní ifprohlášení. Python fori whilesmyčky podporují takovou klauzuli else, která se spouští pouze v případě, že nedojde k předčasnému ukončení smyčky.

Některé jazyky podporují vylamování vnořených smyček; v teoretických kruzích se jim říká víceúrovňové přestávky. Jedním z běžných příkladů použití je hledání vícerozměrné tabulky. To lze provést buď prostřednictvím víceúrovňových přestávek (vylomení N úrovní), jako v bash a PHP, nebo pomocí označených přestávek (vylomení a pokračování na daném štítku), jako v Javě a Perlu. Alternativy k víceúrovňovým přestávkám zahrnují jednotlivé přestávky spolu se stavovou proměnnou, která je testována, aby se vylomila další úroveň; výjimky, které jsou zachyceny na úrovni, která je rozdělena; umístění vnořených smyček do funkce a použití návratu k ukončení celé vnořené smyčky; nebo pomocí štítku a příkazu goto. C neobsahuje víceúrovňovou přestávku a obvyklou alternativou je použít goto k implementaci označené přestávky. Python nemá víceúrovňové přerušení ani pokračování - to bylo navrženo v PEP 3136 a zamítnuto na základě toho, že přidaná složitost nestála za vzácné legitimní použití.

Pojem víceúrovňových přestávek je v teoretické informatice zajímavý , protože dává vzniknout tomu, čemu se dnes říká kosarajuská hierarchie . V roce 1973 S. Rao Kosaraju upřesnil větu o strukturovaném programu tím, že dokázal, že je možné vyhnout se přidávání dalších proměnných ve strukturovaném programování, pokud jsou povoleny víceúrovňové přestávky smyček libovolné hloubky. Kosaraju dále dokázal, že existuje přísná hierarchie programů: pro každé celé číslo n existuje program obsahující víceúrovňové přerušení hloubky n, které nelze přepsat jako program s víceúrovňovými přestávkami hloubky menší než n bez zavedení přidaných proměnné.

Lze také returnvystoupit z podprogramu provádějícího smyčkové příkazy, který se vymyká jak vnořené smyčce, tak podprogramu. Existují i ​​jiné navrhované řídicí struktury pro více přestávek, ale ty jsou obecně implementovány jako výjimky.

David Watt ve své učebnici z roku 2004 používá Tennentův pojem sekvencer k vysvětlení podobnosti mezi víceúrovňovými přestávkami a příkazy k návratu. Watt poznamenává, že třída sekvencerů známá jako únikové sekvencery , definovaná jako „sekvencer, který ukončí provádění textově uzavírajícího příkazu nebo procedury“, zahrnuje jak přestávky ze smyček (včetně víceúrovňových přestávek), tak příkazy return. Jak je však běžně implementováno, návratové sekvencery mohou také nést (návratovou) hodnotu, zatímco sekvenční sekvencer, jak je implementován v současných jazycích, obvykle nemůže.

Smyčkové varianty a invarianty

K vyjádření správnosti smyček se používají varianty smyček a invarianty smyček.

V praxi je smyčková varianta celočíselný výraz, který má počáteční nezápornou hodnotu. Hodnota varianty se musí snižovat během každé iterace smyčky, ale nikdy nesmí být záporná během správného provedení smyčky. Varianty smyček se používají k zajištění ukončení smyček.

Invariant smyčky je tvrzení, které musí být pravdivé před první iterací smyčky a zůstat pravdivé po každé iteraci. To znamená, že když smyčka skončí správně, jsou splněny podmínky ukončení i invariant smyčky. Smyčkové invarianty se používají ke sledování konkrétních vlastností smyčky během postupných iterací.

Některé programovací jazyky, například Eiffel, obsahují nativní podporu pro varianty smyček a invarianty. V ostatních případech je podpora doplňkem, jako je například specifikace Java Modeling Language pro smyčkové příkazy v Javě .

Smyčkový podjazyk

Některé dialekty Lisp poskytují rozsáhlý podjazyk pro popis smyček. Počáteční příklad lze nalézt v konverzačním Lispu Interlisp . Common Lisp poskytuje Loop makro, které implementuje takový podjazyk.

Tabulka křížových referencí systému smyček

Programovací jazyk podmiňovací způsob smyčka předčasný odchod pokračování smyčky předělat zkuste to znovu správnost zařízení
začít střední konec počet sbírka Všeobecné nekonečný varianta invariantní
Ada Ano Ano Ano Ano pole Ne Ano hluboko vnořený Ne
APL Ano Ne Ano Ano Ano Ano Ano hluboko vnořený Ano Ne Ne
C Ano Ne Ano Ne Ne Ano Ne hluboko vnořený hluboko vnořený Ne
C ++ Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený Ne
C# Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený
COBOL Ano Ne Ano Ano Ne Ano Ne hluboko vnořený hluboko vnořený Ne
Lisp Ano Ano Ano Ano pouze vestavěný Ano Ano hluboko vnořený Ne
D Ano Ne Ano Ano Ano Ano Ano hluboko vnořený hluboko vnořený Ne
Eiffelova Ano Ne Ne Ano Ano Ano Ne jedna úroveň Ne Ne Ne pouze celé číslo Ano
F# Ano Ne Ne Ano Ano Ne Ne Ne Ne Ne
FORTRAN 77 Ano Ne Ne Ano Ne Ne Ne jedna úroveň Ano
Fortran 90 Ano Ne Ne Ano Ne Ne Ano hluboko vnořený Ano
Fortran 95 a novější Ano Ne Ne Ano pole Ne Ano hluboko vnořený Ano
Haskell Ne Ne Ne Ne Ano Ne Ano Ne Ne Ne
Jáva Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený Ne nepůvodní nepůvodní
JavaScript Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený Ne
Přírodní Ano Ano Ano Ano Ne Ano Ano Ano Ano Ano Ne
OCaml Ano Ne Ne Ano pole, seznamy Ne Ne Ne Ne Ne
PHP Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený Ne
Perl Ano Ne Ano Ne Ano Ano Ne hluboko vnořený hluboko vnořený Ano
Krajta Ano Ne Ne Ne Ano Ne Ne hluboko vnořený hluboko vnořený Ne
REBOL Ne Ano Ano Ano Ano Ne Ano jedna úroveň Ne Ne
Rubín Ano Ne Ano Ano Ano Ne Ano hluboko vnořený hluboko vnořený Ano Ano
Standardní ML Ano Ne Ne Ne pole, seznamy Ne Ne Ne Ne Ne
Visual Basic .NET Ano Ne Ano Ano Ano Ne Ano jedna úroveň pro každý typ smyčky jedna úroveň pro každý typ smyčky
Prostředí PowerShell Ano Ne Ano Ne Ano Ano Ne ? Ano
  1. a while (true) se pro tento účel nepočítá jako nekonečná smyčka, protože to není vyhrazená jazyková struktura.
  2. a b c d e f g h C'sloop je obecný smyčkový konstrukt, ne konkrétně počítající, i když se k tomu často používá.for (init; test; increment)
  3. a b c Hluboké přestávky lze v APL, C, C ++ a C# provádět pomocí štítků a fotografií.
  4. iterace přes objekty bylapřidánav PHP 5.
  5. a b c Počítací smyčku lze simulovat iterací přes přírůstkový seznam nebo generátor, například Pythonrange().
  6. a b c d e Hluboké přestávky lze dosáhnout použitím zpracování výjimek.
  7. a Neexistuje žádná speciální konstrukce, protože k tomuwhilelze použít funkci.
  8. a Neexistuje žádná speciální konstrukce, ale uživatelé mohou definovat obecné funkce smyčky.
  9. a StandardC ++ 11představilrozsah založený na. VSTLexistujefunkcestd::for_each šablony,která může iterovat nakontejnerechSTLapro každý prvekvolatunární funkci. Funkčnost lzena těchto kontejnerechvytvořit také jakomakro.
  10. Count řízené přemety provádí iteraci přes intervalu celé číslo; předčasný odchod zahrnutím další podmínky pro odchod.
  11. a Eiffel podporuje vyhrazené slovoretry, ale používá se přizpracování výjimek, nikoli při řízení smyčky.
  12. a Vyžadujespecifikační jazyk pro behaviorální rozhraníJava Modeling Language(JML).
  13. a Vyžaduje, aby varianty smyčky byly celá čísla; transfinitní varianty nejsou podporovány. [1]
  14. a D podporuje nekonečné kolekce a schopnost iterovat přes tyto kolekce. To nevyžaduje žádnou speciální konstrukci.
  15. a Hlubokých přestávek lze dosáhnout pomocíGO TOpostupů a postupů.
  16. Common Lisp předchází koncept generického typu kolekce.

Strukturovaný nelokální řídicí tok

Mnoho programovacích jazyků, zejména těch, které upřednostňují dynamičtější styly programování, nabízí konstrukce pro nelokální řídicí tok . Ty způsobí, že tok provedení vyskočí z daného kontextu a obnoví se v nějakém předem deklarovaném bodě. Podmínky , výjimky a pokračování jsou tři běžné druhy nelokálních řídicích konstruktů; existují i ​​exotičtější, jako jsou generátory , korutiny a asynchronní klíčové slovo.

Podmínky

PL/I má asi 22 standardních podmínek (např. ZERODIVIDE SUBSCRIPTRANGE ENDFILE), které lze zvýšit a které lze zachytit: ON podmínkou akce; Programátoři mohou také definovat a používat své vlastní pojmenované podmínky.

Stejně jako nestrukturovaný if lze zadat pouze jeden příkaz, takže v mnoha případech je potřeba GOTO, aby se rozhodlo, kde by měl tok řízení pokračovat.

Některé implementace měly bohužel značnou režii v prostoru i čase (zejména SUBSCRIPTRANGE), takže se mnoho programátorů pokusilo vyhnout se používání podmínek.

Běžné příklady syntaxe:

 ON condition GOTO label

Výjimky

Moderní jazyky mají specializovanou strukturovanou konstrukci pro zpracování výjimek, která nespoléhá na použití GOTOnebo (víceúrovňové) přestávky nebo návraty. Například v C ++ lze psát:

try {
    xxx1                                  // Somewhere in here
    xxx2                                  //     use: '''throw''' someValue;
    xxx3
} catch (someClass& someId) {             // catch value of someClass
    actionForSomeClass 
} catch (someType& anotherId) {           // catch value of someType
    actionForSomeType
} catch (...) {                           // catch anything not already caught
    actionForAnythingElse
}

catchVýše lze použít libovolný počet a rozmanitost klauzulí. Pokud neexistuje catchkonkrétní shoda s konkrétním throw, ovládací prvek se převede zpět prostřednictvím volání podprogramů a/nebo vnořených bloků, dokud catchnení nalezeno párování nebo dokud není dosaženo konce hlavního programu, kdy je program násilně zastaven pomocí vhodné chybové zprávy.

Prostřednictvím vlivu C ++ catchje klíčové slovo vyhrazené pro deklaraci obslužné rutiny výjimky shody vzorů v jiných dnes populárních jazycích, jako je Java nebo C#. Některé další jazyky, jako je Ada, používají klíčové slovo exceptionk zavedení obsluhy výjimek a pak mohou dokonce použít jiné klíčové slovo ( whenv Ada) pro porovnávání vzorů. Několik jazyků, jako je AppleScript, obsahuje zástupné symboly v syntaxi obsluhy výjimek, aby automaticky extrahovaly několik informací, když dojde k výjimce. Tento přístup je doložen níže on errorkonstruktem z AppleScript:

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 must not do that"
end try

Učebnice Davida Watta z roku 2004 také analyzuje zpracování výjimek v rámci sekvencerů (představeno v tomto článku v části o předčasných odchodech ze smyček). Watt poznamenává, že abnormální situace, obvykle ilustrovaná aritmetickými přetečeními nebo selháním vstupu/výstupu, jako soubor nebyl nalezen, je druh chyby, která „je detekována v nějaké nízkoúrovňové programové jednotce, ale [pro kterou] je obsluha přirozeněji umístěna v programové jednotce na vysoké úrovni “. Program může například obsahovat několik volání ke čtení souborů, ale akce, kterou je třeba provést, když soubor není nalezen, závisí na smyslu (účelu) příslušného souboru v programu, a proto nelze rutinu zpracování této neobvyklé situace provést. umístěný v systémovém kódu nízké úrovně. Watts dále poznamenává, že zavedení testování stavových příznaků ve volajícím, jak by to zahrnovalo strukturované programování s jedním výstupem nebo dokonce (vícevýstupové) sekvencery návratu, vede k situaci, kdy „kód aplikace má tendenci být přeplněn testy stavových příznaků“ a že "programátor může zapomenout nebo líně vynechat testování stavového příznaku. Ve skutečnosti jsou abnormální situace reprezentované stavovými příznaky ve výchozím nastavení ignorovány!" Watt poznamenává, že na rozdíl od testování stavových příznaků mají výjimky opačné výchozí chování , což způsobí ukončení programu, pokud se programátor výjimku výslovně nějakým způsobem nezabývá, případně přidáním explicitního kódu, který ji bude ignorovat. Na základě těchto argumentů Watt dochází k závěru, že skokové sekvencery nebo únikové sekvencery nejsou tak vhodné jako vyhrazený sekvencer výjimek se sémantikou diskutovanou výše.

V Object Pascal, D, Java, C#a Python finallylze do trykonstrukce přidat klauzuli . Bez ohledu na to, jak kontrola ponechává trykód uvnitř finallyklauzule, je zaručeno, že se spustí. To je užitečné při psaní kódu, který se po dokončení zpracování musí vzdát nákladného zdroje (například otevřeného souboru nebo připojení k databázi):

FileStream stm = null;                    // C# example
try
{
    stm = new FileStream("logfile.txt", FileMode.Create);
    return ProcessStuff(stm);             // may throw an exception
} 
finally
{
    if (stm != null)
        stm.Close();
}

Protože je tento vzor poměrně běžný, má C# speciální syntaxi:

using (var stm = new FileStream("logfile.txt", FileMode.Create))
{
    return ProcessStuff(stm); // may throw an exception
}

Při opuštění using-bloku kompilátor zaručuje, že je stmobjekt uvolněn, účinně váže proměnnou do proudu souboru a abstrahuje od vedlejších účinků inicializace a uvolnění souboru. K podobnému účinku se používá withpříkaz Pythonu a argument Rubyho bloku k File.open.

Všechny výše uvedené jazyky definují standardní výjimky a okolnosti, za nichž jsou vyvolány. Uživatelé mohou vyvolat vlastní výjimky; ve skutečnosti C ++ umožňuje uživatelům házet a chytat téměř jakýkoli typ, včetně základních typů jako int, zatímco jiné jazyky jako Java nejsou tak tolerantní.

Pokračování

Asynchronní

C# 5.0 zavedlo asynchronní klíčové slovo pro podporu asynchronních I/O v „přímém stylu“.

Generátory

Generátory , známé také jako semikorutiny, umožňují dočasně odevzdat řízení spotřebitelské metodě, obvykle pomocí yieldklíčového slova ( popis výtěžku ). Stejně jako klíčové slovo async podporuje programování v „přímém stylu“.

Coroutines

Coroutines jsou funkce, které si mohou navzájem poskytovat kontrolu - forma kooperativního multitaskingu bez vláken.

Coroutines lze implementovat jako knihovnu, pokud programovací jazyk poskytuje buď pokračování, nebo generátory - takže rozdíl mezi korutinami a generátory v praxi je technický detail.

Křížová reference toku nelokálního ovládání

Programovací jazyk podmínky výjimky generátory/korutiny asynchronní
Ada Ne Ano ? ?
C Ne Ne Ne Ne
C ++ Ne Ano ano, pomocí BOOST ?
C# Ne Ano Ano Ano
COBOL Ano Ano Ne Ne
Lisp Ano Ne ? ?
D Ne Ano Ano ?
Eiffelova Ne Ano ? ?
Erlang Ne Ano Ano ?
F# Ne Ano Ano Ano
Jít Ne Ano Ano ?
Haskell Ne Ano Ano Ne
Jáva Ne Ano Ne Ne
JavaScript ? Ano Ano Ano
Cíl-C Ne Ano Ne ?
PHP Ne Ano Ano ?
PL/I Ano Ne Ne Ne
Krajta Ne Ano Ano Ano
REBOL Ano Ano Ne ?
Rubín Ne Ano Ano ?
Rez Ne Ano experimentální Ano
Scala Ne Ano prostřednictvím experimentálního rozšíření prostřednictvím experimentálního rozšíření
Tcl prostřednictvím stop Ano Ano přes smyčku událostí
Visual Basic .NET Ano Ano Ne ?
Prostředí PowerShell Ne Ano Ne ?

Navrhované řídicí struktury

Ve spoof Datamation článku v roce 1973 R. Lawrence Clark navrhl, že prohlášení GOTO by mohlo být nahrazeno příkazem COMEFROM , a poskytuje několik zábavných příkladů. COMEFROM byl implementován v jednom esoterickém programovacím jazyce s názvem INTERCAL .

Článek Donalda Knutha z roku 1974 „Structured Programming with go to Statements“, identifikuje dvě situace, které nebyly pokryty výše uvedenými řídicími strukturami, a uvedl příklady kontrolních struktur, které by tyto situace mohly zvládnout. Navzdory své užitečnosti se tyto konstrukty dosud nedostaly do běžných programovacích jazyků.

Smyčka s testem uprostřed

V roce 1972 navrhl Dahl následující :

   loop                           loop
       xxx1                           read(char);
   while test;                    while not atEndOfFile;
       xxx2                           write(char);
   repeat;                        repeat;

Pokud xxx1 vynecháme, dostaneme smyčku s testem nahoře (tradiční while smyčka). Pokud xxx2 vynecháme, dostaneme smyčku s testem ve spodní části, což odpovídá smyčce do while v mnoha jazycích. Pokud je while vynechán, dostaneme nekonečnou smyčku. Konstrukce Zde si lze představit jako dělat smyčka s while kontrole ve středu. Proto tato jediná konstrukce může nahradit několik konstrukcí ve většině programovacích jazyků.

Jazyky postrádající tuto konstrukci jej obecně napodobují pomocí ekvivalentního idiomu nekonečné smyčky:

while (true) {
    xxx1
    if (not test)
        break
    xxx2
}

Možnou variantou je povolit více než jeden během testování; ve smyčce, ale zdá se , že použití exitwhen (viz další část) tento případ lépe pokryje.

V Ada lze výše uvedenou smyčkovou konstrukci ( smyčka - zatímco - opakovat ) reprezentovat pomocí standardní nekonečné smyčky ( smyčka - koncová smyčka ), která má uprostřed klauzuli exit (nezaměňovat s příkazem exitwhen v následující části ).

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;

Pojmenování smyčky (jako Read_Data v tomto příkladu) je volitelné, ale umožňuje opuštění vnější smyčky několika vnořených smyček.

Několik předčasných odchodů/výstupů z vnořených smyček

To navrhl Zahn v roce 1974. Zde je představena upravená verze.

   exitwhen EventA or EventB or EventC;
       xxx
   exits
       EventA: actionA
       EventB: actionB
       EventC: actionC
   endexit;

exitwhen se používá k určení událostí, které mohou nastat v rámci xxx , jejich výskyt je indikován použitím názvu události jako příkazu. Dojde -li k nějaké události, provede se příslušná akce a poté řízení přejde těsně po ukončení . Tato konstrukce poskytuje velmi jasné oddělení mezi určením, že nějaká situace platí, a akcí, která má být v dané situaci provedena.

exitwhen je koncepčně podobný zpracování výjimek a výjimky nebo podobné konstrukce se pro tento účel používají v mnoha jazycích.

Následující jednoduchý příklad zahrnuje hledání dvojrozměrné tabulky pro konkrétní položku.

   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;

Bezpečnostní

Jedním ze způsobů, jak zaútočit na kus softwaru, je přesměrovat tok provádění programu. K obraně proti těmto útokům se používá řada technik integrity toku řízení , včetně zásobníků , ochrany proti přetečení vyrovnávací paměti , stínových zásobníků a ověření vtable ukazatelem.

Viz také

Reference

Další čtení

  • Hoare, CAR „Oddíl: Algoritmus 63“, „Rychlé řazení: Algoritmus 64“ a „Najít: Algoritmus 65“. Comm. ACM 4, 321-322, 1961.

externí odkazy