Skok (informatika)
Skok (anglicky jump nebo branch) je instrukce, která narušuje normální způsob provádění 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.
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:
- nepodmíněný skok (anglicky unconditional jump) – skok se provede vždy při vykonávání instrukce skoku
- podmíněný skok (anglicky 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 if
podmínka then
první větev else
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 while
podmínka do
tělo cyklu).
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í).
Používání skoků v procesorech
V instrukčním kódu většiny procesorů je skok implementován změnou hodnoty v registru čí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 registru procesoru nebo na vybraném místě 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).
U moderních procesorů je podmíněný skok kvůli pipeliningu, kterým se vyznačuje superskalární architektura, velice „drahá“ operace z hlediska času zpracování – procesor zpracovává několik instrukcí současně nebo dokonce provádí instrukce na přeskáčku (instruction scheduling), takže 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é RISCové 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í frontu a načíst do ní instrukce ze správné větve.
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 registru čí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ř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á hodnota s rozsahem menším, než je rozsah čítače instrukcí (např. 1 bajt s rozsahem −128 až +127 slov od aktuální pozice v kódu)
- dlouhý relativní skok (long jump) – do registru se přičítá rozsahem stejná hodnota, jako je rozsah čítače instrukcí
Jiné přístupy
Část (RISCový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 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 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ého režimu).
Specifika architektury x86
Při programování v assembleru a strojovém kódu architektury x86 se také rozlišuje, zda cílová adresa skoku leží ve stejné oblasti (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.
Od procesoru 80286 přibývá možnost instrukcí skoku změnit úlohu (přepnout proces), což lze označit jako skok ještě delší než dlouhý; u procesoru 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í adrese, ale dochází k změně fyzické adresy (tato technika patrně nemá jiné využití než jako úmyslná snaha znesnadnit reverzní inženýrství).
Používání skoků v programovacích jazycích
Nižší programovací jazyky obvykle přebírají ze strojového kódu přímo příkaz skoku. Starší vyšší (imperativní) programovací jazyky mají obvykle konstrukci podobnou
IF
podmínka THEN
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ého programování nabízejí konstrukce jako rozvětvení, podmíněný příkaz, cykly a volá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 jazyku C) respektive last a next (např. v jazyku 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ů.
Autorství podmíněného skoku
Za vynálezce podmíněného skoku je považována Ada Lovelace, první programátorka, spolupracovnice Charlese Babbage, vývojáře prvního mechanického počítače.