goto (z anglického go to - "go to") - operátor nepodmíněného skoku (skok na konkrétní bod v programu, označený číslem řádku nebo štítkem) v některých programovacích jazycích . V některých jazycích může mít operátor nepodmíněné větve jiný název (například jmpv assembleru ).
Příkaz se zpravidla gotoskládá ze dvou částí: samotného příkazu a štítku označujícího cílový bod skoku v programu: . Návěští v závislosti na pravidlech jazyka může být buď číslo (jako např. v klasickém BASICu), nebo identifikátor použitého programovacího jazyka. U štítků identifikátorů se štítek obvykle umístí před příkaz, na který se má skočit, a odděluje se od něj dvojtečkou ( ). goto меткаметка:
Akce příkazu jump spočívá v tom, že po jeho provedení budou provedeny další příkazy programu, které jsou v textu bezprostředně za návěštím (do dalšího příkazu skoku, větvení nebo smyčky). U strojových jazyků se instrukce skoku zkopíruje do registru procesoru obsahujícího adresu další instrukce, která se má provést, adresu instrukce označené štítkem.
Operátor gotoje dostupný v jazycích jako Fortran , Algol , Cobol , BASIC , C a C++ , C# , D , Pascal , Perl , Ada , PHP a mnoha dalších. Je také přítomen ve všech jazycích sestavení (obvykle pod názvem jmp, jumpnebo bra(z anglického branch - branch)). Svoboda použití gotose liší jazyk od jazyka. Pokud jej lze v assembleru nebo jazycích jako Fortran použít libovolně (je povoleno přenášet řízení uvnitř větve podmíněného operátoru nebo uvnitř těla smyčky či procedury), pak v jazycích vyšší úrovně je jeho použití omezené: zpravidla je gotozakázáno přenášet řízení mezi různými procedurami a funkcemi pomocí uvnitř vybraného bloku příkazů, mezi větvemi podmíněného příkazu a příkazu s výběrem z více možností.
gotochybí v některých jazycích na vysoké úrovni (např. Forth ). Pascal goto původně nebyl zahrnut, ale nedostatek dostupných jazykových nástrojů donutil Niklause Wirtha jej přidat. Ve svých pozdějších jazycích Wirth stále opouštěl goto: tento operátor není v Module-2 , ani v Oberon a Component Pascal . Java má vyhrazené slovo goto , ale nenese žádné funkce – v jazyce neexistuje operátor nepodmíněného skoku (přeskok však lze provést [1] ). Zároveň byly v jazyce zachovány štítky - lze je použít k ukončení vnořených smyček pomocí operátorů breaka continue.
Operátor gotove vyšších jazycích je terčem kritiky, protože jeho nadměrné používání vede k vytvoření nečitelného „ špagetového kódu “. Tento úhel pohledu se poprvé odrazil v článku Edsgera Dijkstra „Argumenty proti prohlášení GOTO“, [2] který si všiml, že kvalita programového kódu je nepřímo úměrná počtu prohlášení gotov něm. Článek se stal široce známým mezi teoretiky i praktiky programování, v důsledku čehož gotobyly výrazně přepracovány názory na použití operátoru. Ve své další práci Dijkstra doložil skutečnost, že u kódu bez gotoněj je mnohem snazší zkontrolovat formální správnost .
Kód C gotoje obtížně formátovatelný, protože může narušit hierarchii provádění ( paradigma strukturovaného programování ), a proto nemusí být odrážky určené k zobrazení struktury programu vždy správně nastaveny. gototaké zasahuje do optimalizací řídicích struktur kompilátorem. [3]
Některá použití gotomohou způsobit problémy s logikou provádění programu:
Argumenty proti operátorovi gotose ukázaly být natolik závažné, že ve strukturovaném programování začaly být považovány za vysoce nežádoucí. To se odrazilo v návrhu nových programovacích jazyků. Například to gotobylo zakázáno v Javě a Ruby . V řadě moderních jazyků je stále ponechán z důvodů účinnosti v těch vzácných případech, kdy je použití gotooprávněné. Byl tedy gotozachován v Adě , jednom z nejpromyšlenějších jazyků z hlediska architektury v historii. [4] V těch moderních jazycích na vysoké úrovni, kde byl tento operátor zachován, však jeho použití zpravidla podléhá přísným omezením, která brání použití nejnebezpečnějších metod jeho aplikace: např. je zakázáno předávat řízení z vnějšku smyčky, procedury nebo funkce uvnitř. Jazykový standard C++ zakazuje obejít inicializaci proměnné pomocí goto.
Je formálně prokázáno ( Boehm-Jacopiniho teorém ), že aplikace gotoje volitelná, to znamená, že neexistuje takový program, se gotokterým by se bez ní nedalo přepsat s plnou funkčností (avšak možná se ztrátou efektivity).
V praktickém programování je použití gotoněkdy považováno za přijatelné, když jiné jazykové nástroje neimplementují nebo efektivně neimplementují požadovanou funkcionalitu.
Hlavním kritériem použitelnosti gotoje neporušení použitého programovacího paradigmatu (v příkladech níže se jedná o strukturované programování ), jinak je výsledek plný nejrůznějších vedlejších efektů a těžko dohledatelných chyb.
Některé jazyky nemají operátory ukončení smyčky nebo odkazují pouze na vnořenou smyčku , ve které se nacházejí (například breakv continueC). Použití gotopro ukončení několika vnořených smyček najednou v tomto případě značně zjednodušuje programový kód, eliminuje potřebu používat pomocné proměnné proměnné a podmíněné příkazy .
Další řešení tohoto problému je umístit vnořené smyčky do samostatné procedury a použít příkaz exit procedure a v jazycích s podporou výjimek vyvolat výjimku, jejíž popisovač je umístěn mimo smyčky. Taková řešení jsou však méně účinná kvůli režii implementace, zejména pokud je odpovídající část kódu volána vícekrát.
Příklad v C++:
int matice [ n ][ m ]; int hodnota ; ... for ( int i = 0 ; i < n ; ++ i ) for ( int j = 0 ; j < m ; ++ j ) if ( matice [ i ][ j ] == hodnota ) { printf ( "hodnota %d nalezena v buňce (%d,%d) \n " , hodnota , i , j ); //jednat v případě nalezení goto end_loop ; } printf ( "hodnota %d nenalezena \n " , hodnota ); //jednat, pokud nebyl nalezen end_loop : ;Přímým způsobem, jak se toho zbavit goto , je vytvořit další příznakovou proměnnou, která signalizuje opuštění vnější smyčky (po opuštění vnitřní smyčky s break ) a obejít blok kódu, který se provede, když hodnota není nalezena.
Beze změny struktury kódu je problém vyřešen, pokud vám příkaz break(nebo jeho ekvivalent) umožňuje opustit několik vnořených bloků najednou, jako v Javě nebo Ada . Příklad Java:
int [][] matice ; int hodnota ; ... vnější : { for ( int i = 0 ; i < n ; i ++ ) for ( int j = 0 ; j < m ; j ++ ) if ( matice [ i ][ j ] == hodnota ) { Systém . ven . println ( "hodnota " + hodnota + " nalezená v buňce (" + i + "," + j + ")" ); rozbít vnější ; } Systém . ven . println ( "hodnota " + hodnota + " nenalezeno" ); }Nejelegantnějším způsobem, jak se vymanit z vnořené smyčky, je PHP [5] . Po příkazu breakmůžete zadat počet cyklů, které se mají opustit:
for ( $i = 0 ; $i < $Imax ; ++ $i ) { // ... for ( $j = 0 ; $j < $Jmax ; ++ $j ) { // ... if ( podmínka ) přestávka 2 ; // ... } // ... }Pokud jazyk nemá zařízení pro zpracování výjimek , lze příkaz goto použít k přerušení "normálního" provádění kódu a skoku na konečný kód, aby se uvolnila obsazená paměť a další závěrečné akce. Příklad v jazyce C:
int fn ( int * presult ) { int sts = 0 ; TYPE entity , other_entity = NULL ; TYPE2 entity2 = NULL ; if ( ! ( entita = create_entity () ) ) { sts = ERROR_CODE1 ; goto exit0 ; } pokud ( ! něco udělat ( entita ) ) { sts = ERROR_CODE2 ; goto exit1 ; } if ( podmínka ) { if ( ! ( entita2 = vytvořit_jinou_entitu () ) ) { sts = ERROR_CODE3 ; goto exit1 ; } if ( ( * presult = do_another_thing ( entita2 ) == NEGATIVNÍ ) { sts = ERROR_CODE4 ; goto exit2 ; } } jinak { if ( ( * presult = udělat_něco_speciálního ( entita ) == NEGATIVNÍ ) { sts = ERROR_CODE5 ; goto exit2 ; } } exit2 : if ( entita2 ) zničit_jinou_entitu ( entita2 ); exit1 : zničit_entitu ( entita ); exit0 : return sts ; }Bez goto by byl takový kód zbytečně zahlcen mnoha dalšími podmíněnými příkazy if.
Dalším platným použitím nepodmíněného skoku je kód, který je automaticky generován, jako jsou lexery a analyzátory generované softwarovými nástroji. Kód generovaný utilitami yacc , lex , bison je tedy plný příkazů goto, ale tento kód v zásadě není určen pro lidské vnímání a editaci a jeho správnost je zcela určena správností nástroje, který jej vytváří.
Je to nezbytný operátor a používá se všude. V průběhu let se intenzita jeho používání nemění. Většina výpočetních platforem navíc podporuje tak účinný nástroj, jako je indexovaná nepodmíněná větev, která umožňuje minimální čas (několik strojových instrukcí, až jednu) k převedení řízení na jeden z mnoha podprogramů, jejichž výběr je dán obsahem. jednoho z registrů procesoru. K tomu však musí být začátky (vstupní body) všech rutin v této sadě umístěny v paměti RAM s pevným krokem. Vzhledem k tomu, že posledně jmenované je obtížné implementovat pomocí jazyků na vysoké úrovni, indexovaný nepodmíněný skok v nich obvykle není k dispozici, je nahrazen méně efektivním vyhledáváním v tabulce.
MS-DOS a Windows | Běžné příkazy|
---|---|
| |
Viz také: Seznam příkazů DOS Seznam příkazů operačního systému Microsoft |