Skok (informatika): Porovnání verzí

Smazaný obsah Přidaný obsah
Addbot (diskuse | příspěvky)
m Bot: Odstranění 9 odkazů interwiki, které jsou nyní dostupné na Wikidatech (d:q813911)
Přepsání textu
Řádek 1:
[[Soubor:Podminene vetveni vyvojovy diagram.png|thumb|right|220px|[[Vývojový diagram]] podmíněného větvení (podmíněného skoku)]]
 
'''Skok''' ({{Vjazyce|en}} {{Cizojazyčně|en|''jump''}} nebo {{Cizojazyčně|en|''branch''}}) je [[instrukce]], která narušuje normální způsob provádění [[počítačový program|počítačového programu]] instrukce po instrukci (sekvenčně). Zatímco po provedení jakékoli jiné instrukce se pokračuje prováděním instrukce následující, po provedení skoku se pokračuje instrukcí na jiné určené adrese. Jediným skokem lze realizovat buď přeskočení nebo opakování části programu.
'''Skok''' (angl. jump, branch) je změna v sekvenčním vykonávání [[počítačový program|počítačového programu]]. Nižší [[programovací jazyk]]y a [[strojový kód]] mají přímo příkaz skoku, vyšší ([[imperativní programování|imperativní]]) programovací jazyky používají této konstrukce jen zřídka, aby bylo zachováno [[strukturované programování]], používají většinou [[cyklus (informatika)|cykly]] a volání [[funkce (programování)|funkcí]], procedur a metod.
 
Skoky jsou základní prostředek k '''větvení programu''' – rozhodnutí, která část programu se má provádět, na základě výsledku předcházejícího výpočtu. Aby větvení mohlo být ovlivňováno i jinak než nastavením různých cílových adres skoku, používají se podmíněné skoky:
Nejobecnější skok ve vyšších programovacích jazycích se obvykle označuje ''goto''. Blízko mají ke skoku i příkazy ''break'' a ''continue'' (např. v [[C (programovací jazyk)|jazyku C]]) respektive ''last'' a ''next'' (např. v jazyku [[perl]]). Pomocí skoku se implementují řídící struktury ''if'', ''[[while-do cyklus|while]]'', ''[[switch (programování)|switch]]'', ''[[for cyklus|for]]'', a další.
* '''nepodmíněný skok''' ({{Vjazyce|en}} {{Cizojazyčně|en|''unconditional jump''}}) – skok se provede vždy při vykonávání instrukce skoku
* '''podmíněný skok''' ({{Vjazyce|en}} {{Cizojazyčně|en|''conditional jump''}}) – při vykonávání instrukce skoku se buď provede skok nebo se bude pokračovat následující instrukcí v závislosti na výsledku předcházejícího výpočtu nebo vyhodnocení zadané podmínky
 
Pomocí kombinace jednoho podmíněného a jednoho nepodmíněného skoku lze vytvořit dvoucestné větvení programu (jestliže je splněna podmínka, proveď první větev, jinak druhou větev – konstrukce <code>if</code> podmínka <code>then</code> první větev <code>else</code> druhá větev), nebo cyklus, jehož provádění je řízeno zadanou podmínkou (pokud je splněna podmínka, proveď tělo cyklu a jdi znovu na vyhodnocení podmínky – konstrukce <code>while</code> podmínka <code>do</code> tělo cyklu).
Principiálně existují dva druhy skoků:
* '''nepodmíněný skok''' (angl. unconditional jump) – provede se vždy bez ohledu na výsledek předcházejícího výpočtu nebo stav programu
* '''podmíněný skok''' (angl. conditional jump) – provede se jen v případě, že je splněna zvolená podmínka
 
Nedisciplinovaným používáním instrukcí skoku lze vytvořit programy, jejichž chování je velmi obtížné zkontrolovat (u vlastních programů) nebo zjistit (u cizích programů). Vyšší programovací jazyky se proto snaží používání libovolných skoků omezit nebo zcela znemožnit zaváděním programových konstrukcí ([[strukturované programování]]).
Podmíněný skok lze využít k:
* '''větvení programu''' – výběr z alternativ - implementace příkazu ''if'' nebo ''switch''/''case''.
* '''vytvoření cyklu''' (smyčky) - skočí se podle splnění podmínky cyklu - implementace příkazů ''while'' nebo ''for''.
 
== ImplementacePoužívání skokuskoků v [[procesor]]ech ==
 
V [[strojový kód|instrukčním kódu]] většiny procesorů je skok implementován změnou hodnoty v [[Registr procesoru|registru]] [[čítač instrukcí|čítače instrukcí]]. Cílová adresa skoku může být zadána jako parametr instrukce skoku, nebo může být předem nastavena ve vybraném [[registr procesoru|registru procesoru]] nebo na vybraném místě [[vnitřní paměť|vnitřní paměti]]. U podmíněných skoků se rozhoduje o provedení skoku podle hodnoty vybraného bitového příznaku, obsahu zvoleného registru nebo buňky paměti, případně podle výsledku určité operace (sniž hodnotu registru o 1 a pokud není výsledek 0, proveď skok).
== Implementace skoku v [[procesor]]ech ==
 
U moderních procesorů je podmíněný skok kvůli [[pipelining]]u, kterým se vyznačuje [[superskalární architektura]], velice „drahá“ operace z hlediska času zpracování - procesor provádízpracovává instrukceněkolik nainstrukcí přeskáčkusoučasně (instructionnebo scheduling) a zároveňdokonce provádí víceinstrukce instrukcína současněpřeskáčku (vizinstruction [[pipelining]], [[superskalární architektura]]scheduling), takže procesor by pro zrychlení výpočtu by potřeboval vědět, která instrukce bude za skokem následovat, ještě dříve než je možné vyhodnotit splnění podmínky skoku. Některé [[RISC]]ové procesory (např. [[SPARC]]) to řeší pravidly typu „ještě dvě instrukce za skokem se provedou bez ohledu na výsledek podmínky skoku“, obvyklejším řešením je odhadnout (s využití informací o předchozích průchodech danou částí programu), která varianta skoku nastane, a v případě omylu zahodit rozpracované instrukce ze špatné větve, vyprázdnit [[instrukční fronta|instrukční frontu]] a načíst do ní instrukce ze správné větve.
Skok v [[strojový kód|instrukční síti]] většiny procesorů je implementován pomocí zápisu hodnoty nebo přičtení hodnoty do [[Registr procesoru|registru]] [[čítač instrukcí|čítače instrukcí]].
Skok lze potom realizovat jako:
 
Aby se omezilo množství položek, které je potřeba v programu modifikovat při jeho zavedení na jinou adresu v paměti, realizují se některé skoky přičtením hodnoty do [[Registr procesoru|registru]] [[čítač instrukcí|čítače instrukcí]] (autorelativní adresování). Navíc protože v programech jsou poměrně časté skoky o malý počet instrukcí, může mít přičítaná hodnota mnohem menší rozsah než celá adresa, čímž lze v instrukci ušetřit několik bajtů místa. Proto mohou být k dispozici různé druhy skoků:
* '''skok absolutní''' - do registru čítače instrukcí se [[přiřazení|přiřadí]] hodnota
* '''skok relativní''' - do registru čítače instrukcí se přičte hodnota
** '''krátký relativní skok''' (short jump) - do registru se přičítá rozsahem menší hodnota, než je rozsah čítače instrukcí (např. 1&nbsp;bajt s rozsahem −128 až +127 bitových slov od aktuální pozice v kódu); využívá se toho, že skoky o malý počet instrukcí jsou ve spustitelném kódu poměrně časté a v instrukční sadě CISC tak lze ušetřit několik bajtů místa
** '''dlouhý relativní skok''' (long jump) - do registru se přičítá rozsahem stejná hodnota, jako je rozsah čítače instrukcí
 
* '''skok absolutní''' - do registru čítače instrukcí se [[přiřazení|přiřadí]] hodnota
U moderních procesorů je podmíněný skok velice „drahá“ operace z hlediska času zpracování - procesor provádí instrukce na přeskáčku (instruction scheduling) a zároveň provádí více instrukcí současně (viz [[pipelining]], [[superskalární architektura]]), takže procesor by pro zrychlení výpočtu potřeboval vědět, která instrukce bude za skokem následovat ještě dříve než je možné vyhodnotit splnění podmínky skoku. Některé [[RISC]]ové procesory (např. [[SPARC]]) to řeší pravidly typu „ještě dvě instrukce za skokem se provedou bez ohledu na výsledek podmínky skoku“, obvyklejším řešením je odhadnout (s využití informací o předchozích průchodech danou částí programu), která varianta skoku nastane a v případě omylu zahodit rozpracované instrukce ze špatné větve, vyprázdnit [[instrukční fronta|instrukční frontu]] a načíst do ní instrukce ze správné větve.
* '''skok relativní''' - do registru čítače instrukcí se přičte hodnota
** '''krátký relativní skok''' (short jump) - do registru se přičítá rozsahemhodnota menšís hodnotarozsahem menším, než je rozsah čítače instrukcí (např. 1&nbsp;bajt s rozsahem −128 až +127 bitových slov od aktuální pozice v kódu); využívá se toho, že skoky o malý počet instrukcí jsou ve spustitelném kódu poměrně časté a v instrukční sadě CISC tak lze ušetřit několik bajtů místa
** '''dlouhý relativní skok''' (long jump) - do registru se přičítá rozsahem stejná hodnota, jako je rozsah čítače instrukcí
 
=== Jiné přístupy ===
Část ([[RISC]]ových) procesorů [[ARM]] pro podmíněné skoky používá princip ignorování následující instrukce, kombinované právě s instrukcí skoku. Mezi instrukcemi, které mají vyhodnocovat určité podmínky, jsou i varianty těch, které mají za úkol ignorovat následující instrukci, pokud je podmínka vyhodnocena jako pravdivá. Samotné ignorování této instrukce (ve které je tato instrukce vykonána jako instrukce NOOP – ''no operation'') je implementováno jedním z příznaků v procesoru, který se v tomto případě nastavuje a nuluje se po vykonání každé další instrukce. Pokud je touto následující instrukcí instrukce skoku, lze tak implementovat podmíněný skok (pro případy, kdy podmínka v předchozí instrukci ''není'' splněna).
 
=== Další instrukce používající skok ===
 
Aby bylo možné vytvářet podprogramy, procesory jsou vybavovány dalšími instrukcemi, které provádějí skoky v programu. Pro volání podprogramů (po jejichž vykonání je potřeba se vrátit na instrukci následující za voláním podprogramu) se používají instrukce, které před provedením skoku uloží adresu následující instrukce ('''návratová adresa z podprogramu'''). K uložení této adresy se mohou používat univerzální nebo speciální registry nebo paměť. Vzhledem k tomu, že volání podprogramů lze vnořovat, pro ukládání návratových adres se používá datová struktura [[zásobník]].
 
Jako zvláštní případ volání podprogramu lze chápat i [[přerušení|programové přerušení (interrupt)]]. Přerušení obvykle nemá jako parametr přímo adresu obslužné rutiny přerušení, ale jenom číslo přerušení v [[Vektor přerušení|tabulce (vektoru) přerušení]]. Navíc se při jeho vyvolání obvykle provádí další činnosti (např. zákaz dalšího přerušení a vstup do [[Privilegovaný režim|privilegovaného režimu]]).
 
=== Specifika architektury x86 ===
 
Při programování v [[assembler]]u a strojovém kódu architektury [[x86]] se také rozlišuje, zda cílová adresa skoku leží ve stejné oblasti ([[Segmentace|segmentu]]) paměti. Skoky tak lze dělit na:
* '''krátké skoky''' (short jump) - Cílovou adresu lze obvykle vyjádřit jako přírůstek aktuální adresy. Obvykle skok na jinou větev podmínky, na konec cyklu, atd.
* '''dlouhé skoky''' (long jump, far jump) - Cílová adresa leží v jiném segmentu paměti, obvykle nepodmíněný skok na podprogram.
 
Jako zvláštní případ skoku (či spíše volání podprogramu) lze chápat i [[programové přerušení]] ([[interrupt]]). Od procesoru [[Intel 80286|80286]] přibývá možnost instrukcí skoku změnit úlohu (přepnout [[počítačový program|proces]]), což lze označit jako skok ještě delší než dlouhý; a vu procesoru [[Intel 80386|80386]] přibývá možnost změnit [[stránkování paměti]] tak, že zpracování procesu zůstává na stejné [[virtuální adresa|virtuální adrese]], ale dochází k změně [[fyzická adresa|fyzické adresy]] (tato technika patrně nemá jiné využití než jako úmyslná snaha znesnadnit [[debugování]] programu - viz [[reverzní inženýrství]]).
 
== Používání skoků v [[programovací jazyk|programovacích jazycích]] ==
 
Nižší [[programovací jazyk]]y obvykle přebírají ze [[strojový kód|strojového kódu]] přímo příkaz skoku. Starší vyšší ([[imperativní programování|imperativní]]) programovací jazyky mají obvykle konstrukci podobnou
 
<code>IF</code> podmínka <code>THEN</code> návěští
 
ze starších verzí jazyka [[BASIC]], která umožňuje provádět libovolné skoky.
 
Novější programovací jazyky v souladu se zásadami [[strukturované programování|strukturovaného programování]] nabízejí konstrukce jako [[podmíněný příkaz]], [[cyklus (informatika)|cykly]] a volání [[funkce (programování)|funkcí]], procedur a metod.
 
Pokud vyšší programovací jazyk vůbec implementuje nejobecnější příkaz skoku, tento příkaz se obvykle nazývá ''goto''. Blízko k příkazu skoku mají příkazy ''break'' a ''continue'' (např. v&nbsp;[[C (programovací jazyk)|jazyku&nbsp;C]]) respektive ''last'' a ''next'' (např. v&nbsp;jazyku&nbsp;[[perl]]).
 
Při překladu do strojového kódu se řídící konstrukce překládají pomocí podmíněných a nepodmíněných skoků.
Jako zvláštní případ skoku (či spíše volání podprogramu) lze chápat i [[programové přerušení]] ([[interrupt]]). Od procesoru [[Intel 80286|80286]] přibývá možnost instrukcí skoku změnit úlohu (přepnout [[počítačový program|proces]]), což lze označit jako skok ještě delší než dlouhý a v procesoru [[Intel 80386|80386]] přibývá možnost změnit [[stránkování paměti]] tak, že zpracování procesu zůstává na stejné [[virtuální adresa|virtuální adrese]], ale dochází k změně [[fyzická adresa|fyzické adresy]] (tato technika patrně nemá jiné využití než jako úmyslná snaha znesnadnit [[debugování]] programu - viz [[reverzní inženýrství]]).
 
== Autorství podmíněného skoku ==
Řádek 43 ⟶ 61:
== Související články ==
* [[Řízení běhu programu]]
* [[Strukturované programování]]
* [[Cyklus (informatika)|Cyklus]]
* [[Nekonečný cyklus]]