Hlavní moderátor Popular Post vEnd 279 Odesláno: 9. Srpen, 2016 Hlavní moderátor Popular Post Share Odesláno: 9. Srpen, 2016 Obtížnost: Osnova: 1. Úvod, co je to switch 2. Kdy a jak použít switch 3. Další možnosti case 4. Ukázky použití 5. Závěr 1. Úvod Zdravím Vás u sedmého návodu pro začínající pawnery. Tímto navážeme na minulý návod (přečtěte si ho) a rozebereme si, k čemu slouží switch a kdy jej použít namísto normálních podmínek. Napřed ale co je to ten switch. Switch (česky přepínač) je struktura, která v konkrétním případě nahrazuje soustavu if – else if – else. Jeho účelem je vykonat ten blok, který odpovídá jeho hodnotě. Proto také přepínač, obecně se dá říct, že přepne na blok dané hodnoty. 2. Kdy a jak použít switch Už jsem řekl, že se používá v konkrétním případě. Tím případem je tato soustava podmínek: . new cislo = 2; if(cislo == 1) { //hodnota je 1 } else if(cislo == 2) { //hodnota je 2 } else if(cislo == 3) { //hodnota je 3 } else { //hodnota je jiná } . Pokud v podmínkách porovnáváme takto hodnoty, lze k tomu použít kratší a přehlednější switch. Syntaxe switche je následovná: . switch(cislo) { case 1: { //hodnota je 1 } case 2: { //hodnota je 2 } case 3: { //hodnota je 3 } default: { //hodnota je jiná } } . Do závorek switche jsme dosadili proměnnou, ze které zjišťuje hodnotu. case je klíčové slovo, které nám zde tvoří větev pro konkrétní hodnotu. Jak je vidět, nahrazuje nám else if a podmínku. Na jedno si musíme dát pozor – je potřeba za case a hodnotu uvést dvojtečku. default je bez hodnoty a plní funkci else – provede se vždy, když hodnota neodpovídá žádnému case. Narozdíl od case ale není nutné jej použít. 3. Další možnosti case Switch dokáže pracovat jak s celými čísly, tak se znaky a desetinnými čísly. . case 1: //zápis pro celé číslo case 'a': //zápis pro znak case 3.14: //zápis pro desetinné číslo . Jazyk nám též umožňuje zapsat v jednom case několik hodnot, když je to třeba, stačí je oddělit čárkou. . case 1, 3, 5: //několika celých čísel case 'a', 'b', 'c': //několik znaků case 3.14, 1.4, 8.2: //několik desetinných čísel (tečka je desetinná čárka) . Pro zajímavost (rozklikněte spoiler): Vývojáři jazyka ale zašli ještě dál, a dokonce nám umožnili použít rozsah hodnot. Rozsah hodnot má tvar od .. do. Ano, rozsah uděláme pomocí dvou teček, nikoliv tří. . case 1 .. 5: //rozsah celých čísel od 1 do 5 case 'a' .. 'z': //rozsah znaků od a do z . Pozor, rozsahy nelze aplikovat na desetinná čísla! . 4. Ukázky použití Před koncem si ještě ukážeme pár příkladů, jak switch používat. Dialogy enum { DIALOG_REGISTER = 1, DIALOG_LOGIN = 2, DIALOG_ADMIN = 3 } public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) { switch(dialogid) { case DIALOG_REGISTER: { //dialog s ID 1 return 1; } case DIALOG_LOGIN: { //dialog s ID 2 return 1; } default: { //dialog s jiným ID (zbývá nám jen ID 3) return 1; } } } . Kombinovaný zápis new cislo = 5; switch(cislo) { case -1: { //hodnota je -1 } case 0 .. 3: { //hodnota je v rozsahu 0 až 3 } case 4, 5: { //hodnota je buď 4, nebo 5 } default: { //hodnota je jiná } } new znak = 'm'; switch(znak) { case '?', '!': { //hodnota je buď ?, nebo ! } case 'a': { //hodnota je a } case 'b' .. 'z': { //hodnota je v rozsahu b až z } } . 5. Závěr Switchem jsme definitivně ukončili téma podmínek. Kromě if, else if a else teď znáte už i switch a víte, kdy a jak ho použít. Poslední varování na závěr: v jiných jazycích (C/C++, C#, Java, Javascript, PHP atd.) se blok case a default ukončuje klíčovým slovem break a neuvádějí se složené závorky. Pro Pawn to prostě neplatí, takže tuto syntaxi si nechte pro ostatní jazyky. Tento návod, stejně jako ty předchozí, je určen pro nováčky, pokročilejší věci byly buďto úplně vynechány, nebo jsou uvedeny ve spoilerech. Přesto, zdá-li se Vám, že jsem něco opomněl, někde jsem se spletl nebo se jen chcete vyjádřit, pište do tohoto tématu. Ověřený návod Tento návod prošel validací, a lze ho proto považovat za ověřený. 5 Link to comment Share on other sites More sharing options...
Tanga 131 Odesláno: 16. Září, 2017 Share Odesláno: 16. Září, 2017 Obtiaznost: **** Pawn je vykonávaný na abstraktnom stroji (Abstract Machine eXecutor). Tento číta výsledný skompilovaný kód a vykonáva dané inštrukcie. Ak narazí na switch(), porovnávanie hodnôt vykonáva automaticky (porovnávací kód sa nenachádza v skompilovanom súbore). 2. Kdy a jak použít switch Okrem toho, že switch vyzerá krajšie, je aj rýchlejší. Rýchlosť budem porovnávať s týmto kódom: compif(x) { if (x == 1) { return; } else if (x == 2) { return; } else if (x == 3) { return; } else if (x == 4) { return; } else { return; } } compswitch1(x) { switch(x) { case 1..4: return; default: return; } } compswitch2(x) { switch(x) { case 3: return; case 2: return; case 4: return; case 1: return; default: return; } } Čím viac hodnôt (case-ov) porovnávate, tým viac sa oplatí používať switch. Porovnanie (GetTickCount()) môže vyzerať nejak takto: [02:55:21] iftime: 14435 [02:55:29] switchtime1: 8038 [02:55:37] switchtime2: 8053 Rovnako testovanie na dvoch hodnotách (case 1..2) (ale viac iterácií): [03:09:03] iftime: 17946 [03:09:17] switchtime1: 14004 [03:09:33] switchtime2: 16093 A testovanie na 30 hodnotách: [03:14:07] iftime: 72057 [03:14:26] switchtime1: 19457 [03:14:43] switchtime2: 19146 Ako je vidieť, switch už moc nenaberá na čase s viac hodnotami. A tiež switch1 má rovnakú rýchlosť ako switch2. 6. Ako funguje switch Prečo je switch rýchlejší? Ostatné (Pawn viacmenej tiež) jazyky používajú tzv. Jump table. Najprv ukážem ako vyzerá bežný if (kód vyššie) po skompilovaní: (kod som vytiahol cez oficialny pawndisasm.c) * Niektore zbytocne instrukcie som kvoli prehladnosti odstranil. Kvoli tomu adresy nepojdu "za sebou". * pri je (abstraktny register) miesto v pamati, ktore použiva Pawn AMX, kedze nedokaze porovnat priamo dve premenne. Vsetky operacie sa robia cez pri. Mozete si to predstavit ako premennu s rychlym pristupom. * Okomentoval som to pre lahsie citanie, staci si pozriet komenty a adresy kam to skáče. ; compif(x) ; adresa | instrukcia 00000354 proc compif ; if (x == 1) 0000035c load.s.pri 0000000c ; pri = x 00000364 eq.c.pri 00000001 ; pri != 1? 0000036c jzer 00000380 ; ak plati, skoc na adresu 00000384 (dalsi else if) 0000037c retn ; (neplati) return ; else if (x == 2) 00000384 load.s.pri 0000000c ; pri = x 0000038c eq.c.pri 00000002 ; pri != 2? 00000394 jzer 000003a8 ; ak plati, skoc na 000003a8 000003a4 retn ; return 000003a8 ; ... dalsie else if Porovnáva každý if s danou hodnotou, v prípade, že sa nerovnajú, "preskočí" na ďalší else-if. Ten skok trvá najdlhšie. Jump table V RAM vyzera dana tabulka takto: (vlavo adresy v RAM, vpravo inštrukcia na danej adrese) RAM: -------------------------- | jmptable: | | 0x01: JUMP 0x2349807 | | 0x02: JUMP 0x0938490 | | 0x03: JUMP 0x6454299 | | .. | | 0x2349807 kod z case 1 | | .. | -------------------------- Kód switch (x) {..} sa teda kompilerom prepíše na jump (jmptable + x); Ideálne teda nedochádza k žiadnemu porovnaniu hodnôt, iba k jednému skoku. Switch v Pawn Pawn je teda v tomto trochu iný. Tabulka (v Pawn nazýzvaná "casetbl") sa rovnako vygeneruje, ale nepoužíva sa priamo skok, ale len porovnávanie hodnôt. AMX V reálnom čase porovnáva hodnotu x so všetkými "cases" a až keď nájde rovnakú hodnotu, skočí na danú adresu. compswitch1 z kódu uvedeného vyššie: 00000404 proc compswitch1 0000040c load.s.pri 0000000c ; pri = x 00000414 switch 00000444 ; switch (pri), jump table je na adrese 00000444 ; case 1..4: 00000424 retn ; return - vnutro case 00000428 jump 00000470 ; skoc za casetbl, v pripade ze nenasiel ziadnu hodnotu v tabulke ; case: default 00000438 retn ; return, resp. iny kod 0000043c jump 00000470 ; skoc za "casetbl", teda na dalsi kod 00000444 casetbl 00000004 00000438 ; celkovo 4 moznosti, pri default skoč na 00000438 00000001 00000424 ; case 1: jmp 00000424 00000002 00000424 ; case 2: jmp 00000424 00000003 00000424 00000004 00000424 00000470 ; .. Je teda zrejmé, že "1..4" vygeneruje zápisy pre všetky možnosti medzi tým s rovnakou skokovou adresou. Kód cmpswitch2 vyzerá podobne. Pre stručnosť sem dám len casetbl. 00000478 proc compswitch2 ; .. 000004f4 casetbl 00000004 000004e0 ; 4 zapisy 00000001 000004cc ; x == 1 -> skoc na prvy case 00000002 000004a4 ; x == 2 -> druhy case 00000003 00000490 00000004 000004b8 000004e0 ; .. Rozdiely medzi cmpswitch1 a 2 sú, že každý case má odlišnú adresu kam skočiť. Záver Možno ste si všimli, že hodnoty sú v compswitch2 po skompilovaní zoradené. Kompiler ich zoradil automaticky. The records in the case table are sorted on their value. An abstract machine may take advantage of this lay-out to search through the table with a binary search. (z Pawn Implementer Guide). Podľa zdrojového kódu amx sa však nepoužíva binary search, ale lineárne porovnávanie všetkých hodnôt zaradom. 3 Link to comment Share on other sites More sharing options...
ATomas 286 Odesláno: 16. Září, 2017 Share Odesláno: 16. Září, 2017 (porovnávací kód sa nenachádza v skompilovanom súbore). S tímto bych nesouhlasil. V kompilovanem kodu je vsechno. Ale pri spusteni se cely nahraje do pameti (Tj muzes po spusteni mod smazat ze slozky gamemodes a furt svr pojede (do resetu)). Taky jeden z duvodu proc nema moc smysl resit jestli vytvorit pole o 50 nebo 100 znacich kdyz ma cely kompilovany kod 10MB Link to comment Share on other sites More sharing options...
Tanga 131 Odesláno: 16. Září, 2017 Share Odesláno: 16. Září, 2017 Sry venďo, že ti spamujem do navodu S tímto bych nesouhlasil. V kompilovanem kodu je vsechno. Ale pri spusteni se cely nahraje do pameti (Tj muzes po spusteni mod smazat ze slozky gamemodes a furt svr pojede (do resetu)). Taky jeden z duvodu proc nema moc smysl resit jestli vytvorit pole o 50 nebo 100 znacich kdyz ma cely kompilovany kod 10MB Myslel som to tak, že ak použiješ switch, vo vyslednom subore je len "switch (adresa tabulky)" a samotna casetbl. Porovnavanie hodnot a nasledny skok na tu spravnu hodnotu tam nie je, robí to amx na pozadí. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now