Jump to content
Prosíme všetkých užívateľov, ktorý sa chcú opätovne pripojiť na discord aby znovu spárovali svoje účty kliknutím na "Discord" v navigácií a pripojili sa na server Read more... ×

xhunterx

Uživatel
  • Příspěvků

    167
  • Registrován

  • Aktivní

  • Vítězných dnů

    17

xhunterx last won the day on Červen 10

xhunterx had the most liked content!

Reputace

76 The Truth

About xhunterx

  • Moto
    Meh.

Kontaktní údaje

  • Web
    https://xhunterx.tk
  • Jabber
    samphunter@404.city

Portfolio

  • Github
    samphunter

Návštěvníci

1 160 profile views
  1. xhunterx

    ostatní Discord server pre SA-MP CZ/SK

    Pawno ma Discord server okrem ineho...
  2. No bohužial v školstve SK/CZ známky moc nehovoria o ničom. Ale chcel by som spomenúť ešte jeden praktický problém. Keď dieťa nosí z niečoho 4, a nepracuje na zlepšení, je dosť ťažké v dalších ročníkoch z toho nenosiť 5 (pre mňa španielčina). A keď nespravíš školu kôli predmetu, ktorý ti nejde a nechceš sa mu venovať, stále si nespravil školu... Ideálne by to tak asi byť nemalo, ale nemáme ideálne školstvo.
  3. xhunterx

    ostatní Regitrace feedback

    Ja mam velmi rad prihlasovanie cez Google ucet a respektujem stranky, ktore si dali namahu to implementovat viac. Na Google bezne stacia minimalne povolenia na zobrazenie mailu pri logine, takze to je v pohode podla mna. Facebooku neverim a rozhodne by som ho na login nepouzival. Uprimne sa vzdy pousmejem, ked stranka ma Google a nema FB, ale samozrejme urcite niektory ludia preferuju FB, takze ak to pridas, tak fajn. Co som videl vacsina programatorsky zameranych stranok ako gitlab, bitbucket atd. Facebook taktiez nepodporuju, takze asi niesom sam, co Zuckerbergovi neverim
  4. xhunterx

    návod Práce 2019 - Systémy #4

    sizeof je direktiva kompilatoru, nahradzuje sa pri kompilacii rovnako ako makro. Inak to byt ani nemoze, kedze pawn neuklada velkosti pola pri runtime. Pouzivat dalsiu premennu je preto pomalsie nez pouzit priamo sizeof...
  5. xhunterx

    pomoc RCON Ochrana

    RCON Rozhodne odporúčam vypnúť vzdialený rcon. Stačí dať do configu "rcon 0". Na servery rcon configom vypnúť nejde, odporúčam jednoducho šialene dlhé náhodné heslo. Je možné taktiež spraviť FS, ktorý každú sekundu zmení rcon heslo a prípadne aj kickne online rcon adminov. Cheaty Najčastejšie cheaty sú s0beit + jeho modifikácie a Cleo módy ako parkour, aimbot... Odporúčam si stiahnuť s0beit a osobne vyskúšať všetky funkcie. Je ovela lepšie to skúsiť ako tu mať textový popis.
  6. xhunterx

    ostatní Regitrace feedback

    Tiež by som radil fullname. Vyhnes sa problemom so stredným menom a inými hovadinami okolo toho.
  7. xhunterx

    script h_va variadic functions helper

    Malé include na pomoc s robením variadických funkcíí, čo som dnes spravil, keď som sa hral s assembly. Použitie: Vyžaduje Zeexov compiler 3.10.9+! stock SendClientMessagef(playerid, color, const msg[], ...) { new str[145]; ReusableVarargCallerNative(va_func(format), 3, va_string(str), sizeof(str), va_string(msg)); return SendClientMessage(playerid, color, str); } "format" je native, ktorý chceme zavolať. va_func() je makro, ktoré premení native na premennú, aby sa dalo dať do funkcie. 3 je počet normálnych argumentov vo funkcii. Takže format dostane až argument 4 a viac. va_string je pomocná funkcia, ktorá sa použije na pridanie stringu, ktorý nejde do "...". Takže vo format(str[], size, const fmt[], ...); sa to použije len na str a fmt. Pri volaní SendClientMessagef sa to nepoužíva. Táto funkcia zavolá format takto: format(str, sizeof(str), msg, ...); Podobná funkcia ReusableVarargCaller volá PAWN funkcie (nie native). Inak funguje úplne rovnako. h_va.inc
  8. Emit #2: Funkcie a stack Obtížnost: 7/5 Aneb ako to ten compiler robí? Tento tutoriál vyžaduje Zeexov Compiler verziu 3.10.9+, pretože používa nový operátor emit (nie direktívu). Osnova/obsah: Stack a STK register Lokálne premenné Volanie funkcii a FRM register Parametre funkcii Alokácia lokálnych premenných Volanie native funkcií Praktická motivácia Záver 1. Stack a STK register Stack si vlastne môžete predstaviť ako veľký kus pamäte. Ako veľký sa určuje pri kompilácii amx pomocou #pragma dynamic Kde presne máte uložené veci na stacku zistíte pomocou STK registru. STK je jeden z tých 7+ daľších registrov, ktoré som minule spomenul, ale ďalej neriešil. STK ukazuje na poslednú hodnotou, ktorú ste na stack vložili. Je taktiež dôležité spomenúť, že stack je otočený opačne, takže predchádzajúca hodnota je na adrese STK + 4. STK je samozrejme v bajtoch a premenná v PAWN má bežne 4 bajty, takže STK je vždy násobok 4. Taktiež premenná v PAWN sa volá cell a jej veľkosť sa často zapisuje ako cell size. Pre samp vždy cell size = 4. Inštrukcie PUSH a POP sa teda dajú zapísať ako: PUSH.pri/alt - STK = STK - cell size, [STK] = pri/alt POP.pri/alt - STK = pri/alt = [STK], STK + cell size Ako zistíme hodnotu STK? Ako ju zmeníme? Môžeme použiť inštrukcie: LCTRL 4 - pri = STK SCTRL 4 - STK = pri 4 je v týchto inštrukciách register STK. Iné čísla vám dajú iné registre, ale k tým sa dostaneme neskôr. 2. Lokálne premenné Lokálne premenné su v skutočnosti nenápadne uložené na stacku. new a = 3; vo funkcii v skutočnosti nieje nič viac ako emit PUSH.C 3; s tým, že si to miesto, kde sa premenná nachádza compiler zapämatá pod menom a. Ale xhunterx, ako sa k lokálnym premenným dostaneme, keď môžeme pristupovať len k vrchnej hodnote na stacku? No ja som vám trošku klamal. Odstrániť zo stacku môžeme len vrchnú hodnotu, pretože zo stacku vymazávame posnutím registru STK. Nič nám ale nebráni pozrieť sa na akékoľvek miesto na stacku. Na nájdenie týchto premenných nám slúžia inštrukcie: LOAD.S.pri/alt Offset - Načíta lokálnu premennú z Offset do pri/alt STOR.S.pri/alt Offset - Uloží pri/alt do lokálnej premennej z Offset PUSH.S Offset - Uloží hodnotu lokálnej premennej z Offset na zásobník To nám umožní spraviť napríklad: main() { new a = 1; new b = 2; // t = a; a = b; b = a; // Vymeníme a, b emit LOAD.S.pri a; // Načítame a do pri emit LOAD.S.alt b; // Načítame b do alt emit STOR.S.pri b; // Uložíme pri do b emit STOR.S.alt a; // Uložíme alt do a printf("a = %i, b = %i", a, b); // a = 2, b = 1 } 3. Volanie funkcii a FRM register Teraz vieme ako pracovať s lokálnymi premennými, ale ako to vlastne funguje? Na to sa musíme pozrieť, ako sa voláju funkcie. Povedzme že máme: func(a, b, c) { return a + b + c; } main() { new a = 1, c = 3; func(a, 2, c); return 1; } Toto by vyzeralo v asi nejak takto: Test() { //emit PROC; // PROC je automaticky vygenerované na začiatku každej funkcie // Ručne to písať nemusíme, preto je to zakomentované emit CONST.pri a + b + c; emit RETN; // POZOR! Iné ako RET } main() { new a = 1, c = 3; emit PUSH.S c; // Pushneme c na stack emit PUSH.C 2; // Pushneme 2 na stack emit PUSH.S a; // Pushneme a na stack // Všimnite si, že pushujeme v opačnom poradí. Posledný parameter sa pushuje ako prvý. // To je aby k nim funkcia mohla pristupovať v správnom poradí, keďže ona ich uvidí opačne. // c, ktorú sme dali na kopu papierov bude v tej kope najhlbšie. emit PUSH.C 12; // Počet parametrov * cell size emit CALL Test; } V tomto kóde máme 3 nové inštrukcie. CALL, PROC a RETN. Tieto inštrukcie taktiež používajú 2 nové registre FRM a CIP. CIP jednoducho uchováva adresu inštrukcie, ktorá sa práve vykonáva. Tento register sa neustále mení, ako sa vykonávajú inštrukcie. FRM uchováva STK na začiatku funkcie. CALL Adresa - STK = STK - cell size, [STK] = CIP + 8, CIP = Adresa Ak sa na to pozrieťe, prvé 2 časti vyzerajú ako push. A presne to aj robia. Call pushne CIP + 8 na zásobník. CIP + 8 je adresa dalšej inštrukcie po call, keďže samotná inštrukcia je cell (4 bajty) a Adresa je taktiež cell (4 bajty). Nakonie CALL do CIP vloží adresu Adresa. Tým zaistí, že dalšia inštrukcia, ktorá sa bude vykonávať nebude ďalšia inštrukcia v poradí, ale prvá inštrukcia funkcie, ktorú voláme. A prvá inštrukcia funkcie je vždy PROC. PROC - STK = STK - cell size, [STK] = FRM, FRM = STK Znovu dve časti sú push, konkrétne pushneme starú hodnotu FRM na zásobník. Potom do FRM dáme aktuálnu hodnotu STK. Toto nám umožnuje používať inštrukcie ako LOAD.S.pri. Vďaka FRM vieme spočítať, kde sa premenné nachádzajú. A nakoniec nová inštrukcia RETN. RETN - FRM = [STK], CIP = [STK + 4], STK = STK + 12 + [STK + 8] Kde [STK] je stará hodnota FRM od PROC, [STK+4] je adresa dalšej inštrukcie po CALL, [STK+8] je velkosť parametrov funkcie (naše emit PUSH.C 12;) Táto inštrukcia teda spravý niekoľko vecí. Vráti do FRM pôvodnú hodnotu zo zásobníku, ktorú tam uložil PROC Nastavý dalšiu inštrukciu na hodnotu zo zásobníku, teda na hodnotu, ktorú tam uložil CALL, teda na ďalšiu inštrukciu po CALL Vymaže zo zásobníku všetky uložené hodnoty a parametre funkcie. Stack teda vo vnútry funkcie Test v našom príklade vyzerá takto: STACK = Stary_FRM, Navratova_Adresa, Velkost_Parametrov (=12), a, 2, c Pre úplnosť presné definície tývhto inštrukcií sú. LOAD.S.pri/alt Offset - pri/alt = [FRM + Offset] STOR.S.pri/alt Offset - [FRM + Offset] = pri/alt PUSH.S Offset - STK = STK - cell size, [STK] = [FRM + Offset] Mentálne cvičenie: Pre inštrukcie sú mená lokálnych premenných vlastne len Offset. Aký offset má premenná a v tejto funkcii? Bonus: aký offset má b? Test(b) { new a; return a + b; } 4. Parametre Funkcií Ako ste si mohli všimnúť podla posledného mentálneho cvičenia, parametre funkcie majú vlastne taktiež svoj offset voči FRM. A naozaj aj na ne môžeme pristupovať aj k parametrom funkcie. Napríklad funkcia z cvičenia sa dá napísať aj takto: Test(b) { new a; emit LOAD.S.pri a; emit LOAD.S.alt b; emit ADD; emit RETN; // Návratová hodnota je uložená v pri } 5. Alokácia lokálnych premenných Ako som už písal, lokálne premenné sa alokujú obyčajným pushom. Ak máte new a; vznikne emit PUSH.C 0; new b = 5; vznikne emit PUSH.C 5; Ako sa ale tieto premenné dealokujú? Mohli by sme použiť vždy POP, ale to by bolo pomalé a neefektívne. Miesto totoho existuje inštrukcia STACK. STACK Size - STK = STK + Size Takže ak chcem dealokovať 10 premenných (10 * cell size = 40 bajtov), napíšem emit STACK 40; Takže napríklad funkcia AllocTest() { new a, b, c, d; { new e, f; // Nieco } // Nieco2 } Bude po compilacii vyzerať nejak takto: AllocTest() { emit PUSH.C 0; emit PUSH.C 0; emit PUSH.C 0; emit PUSH.C 0; { emit PUSH.C 0; emit PUSH.C 0; // Nieco emit STACK 8; } // Nieco2 emit STACK 16; } Všimnite si, že v tomto prípade {} ani nepotrebujem, napísal som ich sem len pre prehľadnosť. Ešte stále tu ale máme veľa PUSH.C 0. Čo ak budeme chcieť vela lokálnych premenných. Môžeme to nejak zlepšiť? V podstate áno, ale je to zložité. Za prvé, FRM je register číslo 5, takže LCTRL 5 nám načíta FRM do pri. MOVE.pri/alt - pri = alt/alt = pri FILL Size - Vyplní rozsah od alt, veľkosti Size hodnotou pri. alt musí byť násobok cell size. Test() { emit STACK -20; // Alokujeme 5 * cell size miesta na stacku emit ADDR.alt -20; // Do alt dáme adresu začiatku premenných. emit ZERO.pri; // Nastaví pri na 0 emit FILL 20; // Vyplníme miesto od STK velkosti 20 nulami, čiže vynulujeme našich 5 premenných // Máme 5 lokálnych premenných emit STACK 20; // uvolníme premenné } 6. Volanie native funkcií Native funkcie môžeme volať pomocou inštrukcie: SYSREQ.C Func - Zavolá native funkciu Func Native funkcie sa však chovajú inak, ako normálne funkcie. Na rozdiel od normalných PAWN funkcií si po sebe neupracú, takže všetky premenné, ktoré ste pushli na zásobník musíte vymazať ručne. Príklad volania native funkcie: CallSCM(playerid, color, const str[]) { emit push.s str; // Pushneme posledný parameter emit push.s color; // Pushneme stredný parameter emit push.s playerid; // Pushneme prvý parameter emit push.c 12; // Pushneme velkosť parametrov emit sysreq.c SendClientMessage; // Zavoláme SendClientMessage emit stack 16; // Upraceme zásobník. 12 pre parametre + 4 pre velkosť. // 4x Push * cell size = 16 emit retn; // výsledok native je taktiež v pri, takže môžeme rovno return } Taktiež je dôležité, aby ste native ktorý takto voláte niekde použili mimo emit. Ak daný native nieje nikde použitý normálne, compiler ho nezpozná a crashne (compiler v3.10.9). 7. Praktická motivácia Často chceme vytvoriť funkciu, ktorá berie premnlivý počet argumentov a posunie ich dalšej funkcii, napríklad format. To však spraviť v PAWN je veľmi zložité. Tu je ukážka jedného možného spôsobu, ako na to: Použijeme priamo parametre, ktoré poslali našej funkcii a oklameme format tak, aby si myslel, že sú to parametre pre neho. Samozrejme prvé 2 parametre musíme zmeniť. stock SendClientMessagef(playerid, color, const msg[], ...) { new p, c, stk, str; emit { // Zálohujeme premenné load.s.pri color stor.s.pri c load.s.pri playerid stor.s.pri p // Nastavíme max velkosť pola pre format, argument 2 const.pri 145 stor.s.pri color // Vytvoríme pole na heape a vložíme ho ako argument 1 pre format heap 145 stor.s.alt playerid stor.s.alt str // Uložíme si kópiu na neskôr // Uložíme STK do zálohy lctrl 4 stor.s.pri stk // Nastavíme STK tak, aby format zobral parametre tejto funkcie // ako si pamatáme, stack vo funkcii vyzerá takto // STACK = ..., c, p, OFRM, RETADDR, PARAMSIZE, playerid, color, msg, ... // A FRM ukazuje na OFRM. Ďalej na volanie funkcie chceme na stacku mať // STACK = PARAMSIZE, playerid, color, msg, ... // To znamená, že musíme zobrať FRM a posunúť ho o 8 bajtov (2 celly) lctrl 5 // Získame FRM add.c 8 // Pridáme 8 sctrl 4 // Vložíme do STK // Teraz môžeme pekne zavolať format sysreq.c format // Keďže native po sebe neupratujú, ani nepoužívajú stack // jediné, čo sa volaním zmenilo je pri (return formatu) a samozrejme obsah str // Vrátime parametre zo zálohy load.s.pri c stor.s.pri color load.s.pri p stor.s.pri playerid // Vrátime STK zo zálohy load.s.pri stk sctrl 4 // Zavoláme normálne SendClientMessage push.s str push.s color push.s playerid push.c 12 sysreq.c SendClientMessage stack 16 // Uvolníme string z heapu prec heap -145 // Alebo aj // load.s.pri str // sctrl 2 // 2 = HEA } return 1; } 8. Záver Na záver by som ešte chcel zabohovať na dokumentáciu pawna. 3 verzie PAWN Implementer's Guide v PDF po ruke v pohotovosti, ani jeden nezodpovedá tomu, ako to reálne funguje. Napríklad podla guide je STK pointer na volné misto nad poslednou hodnotou v zásobníku. To ale jednoduchým testom vidíme, že nieje pravda... Podľa guide taktiež CALL robí [STK] = CIP + 5 (inštrukcia má asi mať velkosť 1 bajt). To ale taktiež nieje pravda. Inštrukcie ako ADDR.pri/alt ani v jednej z týchto príručiek niesu, no compiler ich veselo používa. A samozrejme ak dáte native funkcii adresu, ktorá je pod STK, tak crashne server. Nedokážem nájsť ani vidieť žiadny dôvod, prečo by tomu tak malo byť. Nikde inde sa nič také nedeje. No každopádne tu ano, takže super. Anilen hlášku to nenapíše... Ak niekde nájdem na predaj náhradné nervy, tak sa uvidíme pri časti 3. V tej sa pozrieme na skoky a pointery.
  9. Jo, sorry. Tak išlo o to vyjadriť, že toto nieje PAWN. Je to vlastne úplne iný jazyk a hlavne druhý diel ktorý práve píšem fakt sa podla mňa nedá provnávať s manipuláciou bitov. Jop, to niekam zakomponujem.
  10. Ďakujem, zatiaľ plánujem 3 diely. Ak bude záujem a čas, môžem spraviť viac. Praktické príklady u assembleru je dosť ťažké spraviť, pretože ako som písal, praktické je to nepoužívať vôbec ak nerobíte nejaké knižnice. Ale pokúsim sa. Zatial na to nieje dosť znalostí v tomto návode.
  11. Emit #1: Základy Obtížnost: 7/5 Prečo to robiť jednoducho, keď to ide zložito? Tento tutoriál vyžaduje Zeexov Compiler verziu 3.10.9+, pretože používa nový operátor emit (nie direktívu). Osnova/obsah: Disclaimer Globálne Premenné Základné operácie Stack Zlahčováky Operátor emit Záver 1. Disclaimer Emit a amxassembly je určite zaujímavá vec. Je to však podobné atómovej bombe. Je fajn ju mať, ale nikdy ju nechceme použiť. Vyššie jazyky ako PAWN existujú z dobrého dôvodu. Písať kód v assembly je zbytočne zdĺhavé a nebezpečné. Vzniknutý kód je absolútne nečitateľný. Chyby v assembly niesu ako chyby v PAWN, kde vás buď upozorní compiler, alebo vám nefunguje to, čo ste spravili. Pri chybe v emit sa môže stať čokoľvek. Crashe, SendClientMessage začne zobrazovať TextDrawy, 2 + 2 je zrazu 5, mačky naháňajú psy, počítače začnú horieť... Emit vám dokáže spôsobiť chyby v úplne iných častiach serveru a neukázať žiadny náznak, že je to chyba emitu... Ak na to nieste psychicky pripravený, tak radšej prestaňte čítať. Tento tutoríal čítajte na vlastné riziko! Autor nebude zodpovedný za žiadnu škodu, ktorú si spôsobíťe používaním emitu alebo iným používaním týchto informácií! Autor nebude zodpovedný za vaše mentálne zdravie, ak sa pokúsite chápať emity! 2. Globálne premenné Prvá vec, ktorú treba vedieť pri používaní emit sú registre. Registre fungujú podobne ako premenné a pawn ich ma niekoľko 9+. Zatiaľ nás však budú zaujímať len 2: pri a alt. Pri je primárny register. Takmer všetko, čo budeme robiť používa pri. Alt je alternatívny register, ktorý sa používa hlavne keď potrebujeme robiť s 2 číslami. Napríklad ak chceme 2 čísla sčítať. Ďalej musíme vedieť inštrukcie. Inštrukcie sú akési príkazy, ktoré hovoria, čo sa má spraviť. Niektoré inštrukcie za sebou majú .pri alebo .alt, čo určuje, s ktorým registrom chceme pracovať. Napríklad: LOAD.pri Adresa - Načíta hodnotu z adresy Adresa do registra pri LOAD.alt Adresa - Načíta hodnotu z adresy Adresa do registra alt Všeobecne toto zapisujeme ako LOAD.pri/alt Adresa - Načíta hodnotu z [Adresa] do pri/alt Ďalej keď pracujeme s hodnotou na určitej adrese, používame zápis [Adresa]. Takže ešte inak sa to dá zapísať LOAD.pri/alt Adresa - pri/alt = [Adresa] Tento zápis nám hovorí, že zoberieme hodnotu z adresy Adresa a vložíme ju do registru pri alebo alt, podla toho, ktorú inštrukciu použijeme (LOAD.pri alebo LOAD.alt). STOR.pri/alt Adresa - [Adresa] = pri/alt A ako vidíťe, táto inštrukcia STOR nám zase uloží obsah registra na adresu Adresa. Samozrejme sa pravdepodobne pýtate, odkial máte zobrať adresu? Užitočne miesto adresy môžete dať meno globálnej premennej, takže môžeme napríklad spraviť: new a = 1; new b = 2; main() { printf("a = %i, b = %i", a, b); // a = 1, b = 2 // b = a; emit LOAD.pri a; // Načítame a do pri emit STOR.pri b; // Uložíme pri do b printf("a = %i, b = %i", a, b); // a = 1, b = 1 } 3. Základné operácie Samozrejme obvykle nechceme len presúvať hodnoty, ale s nimi niečo počítať. Na to môžeme použiť napríklad niektoré z týchto inštrukcií. CONST.pri/alt Hodnota - pri/alt = Hodnota ADD - pri = pri + alt SUB - pri = pri - alt SUB.alt - pri = alt - pri NEG - pri = -pri SMUL - pri = pri * alt SDIV - pri = pri / alt, alt = pri % alt XCHG - Vymení pri a alt S týmito inštrukciami už môžeme spraviť niečo ako c = a + b; new a = 3; new b = 2; new c; main() { printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 0 // c = a + b; emit LOAD.pri a; // Načítame a do pri emit LOAD.alt b; // Naćítame b do alt emit ADD // sčítame pri a alt a výsledok vložíme do pri emit STOR.pri c; // uložíme pri do c printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 5 } A veľa dalších vecí: new a = 3; new b = 2; new c; main() { printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = 0 // c = -a - b; emit LOAD.pri a; emit NEG; emit LOAD.alt b; emit SUB emit STOR.pri c; printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = -5 // c = a * -b; emit LOAD.pri b; // Načítame b do pri, pretože NEG funguje len na pri emit NEG; // pridáme mínus, takže pri = -b emit XCHG; // presunieme pri do alt, takže alt = -b emit LOAD.pri a; // načítame a do pri emit SMUL; // vynásobíme pri * alt, čiže a * -b emit STOR.pri c; // uložíme výsledok do c printf("a = %i, b = %i, c = %i", a, b, c); // a = 3, b = 2, c = -6 // a = a + 5; emit LOAD.pri a; // Načítame a do pri emit CONST.alt 5; // Načítame 5 do alt emit ADD; // sčítame emit STOR.pri a; // uložíme výsledok do a } 4. Stack Ok, ale čo ak chceme spraviť a * b + c * d; Ak začnete písať tento kód, zistíte, že nemáte kam uložiť medzihodnotu a * b. Ano, môžete skúsiť podvádzať a uložiť ju do r, ale čo ak miesto r to budete chcieť dať priamo do funkcie? Odpoveď je zásobník. Úlohou zásobníka je pre vás podržať hodnoty, ktoré potrebujete. Predstavte si zásobník ako hŕbu papierov. Vždy keď potrebujete si môžete na vrch papier odložiť a neskôr ho z vrchu zobrať, avšak nesmiete sa v tej hŕbe hrabať. Môžete brať a dávať len na vrch. PUSH.pri/alt - Vloží pri/alt na vrch zásobníku. POP.pri/alt - Vloží hodnotu z vrchu zásobníku do pri/alt. Takže môžeme spraviť napríklad: new a = 3, b = 2, c = 4, d = 4; new r; main() { // r = a * b + c * d; emit LOAD.pri a; emit LOAD.alt b; emit SMUL; emit PUSH.pri; // uložíme výsledok na zásobník emit LOAD.pri c; emit LOAD.pri d; emit SMUL; emit POP.alt; // vybereme výsledok prvého náspbenia zo zásobníku emit ADD; emit STOR.pri r; printf("r = %i", r); // r = 22 } Na stack môžeme vložiť viacero hodnôt, napríklad: new a = 1, b = 2, c = 3, d = 4; new r; main() { // r = a + b + c + d; emit LOAD.pri d; emit PUSH.pri; // STACK = d emit LOAD.pri c; emit PUSH.pri; // STACK = c d emit LOAD.pri b; emit PUSH.pri; // STACK = b c d emit LOAD.pri a; emit PUSH.pri; // STACK = a b c d emit POP.pri; // a // STACK = b c d emit POP.alt; // b // STACK = c d emit ADD; emit POP.alt; // c // STACK = d emit ADD; emit POP.alt; // d emit ADD; emit STOR.pri r; printf("r = %i", r); // r = 10 } Možno sa teraz spýtaťe, čo sa stane ak dám POP viac krát ako PUSH? Mačky začnú nahánať psov, alebo možno váš počítač vybuchne. Kdo vie... 5. Zľahčováky Existuje taktiež veľa inštrukcií, ktoré existujú na zľahčenie písanie, napríklad niektoré inštrukcie majú verziu .C, ktorá použije zadanú hodnotu miesto registra. Napr "ADD.C 5" pripočíta k registru pri 5, čiže pri += 5. ADD.C Hodnota - pri = pri + Hodnota SMUL.C Hodnota - pri = pri * Hodnota PUSH.C Hodnota - Vloží Hodnota na zásobník INC.pri/alt - pri/alt = pri/alt + 1 DEC.pri/alt - pri/alt = pri/alt - 1 ZERO.pri/alt - pri/alt = 0 ZERO Adresa - [Adresa] = 0 ... 6. Operátor emit Možno viete, že bežne sa nepoužíva emit ale #emit. emit ani v bežnom compilery pribalenom v samp nieje. Tak prečo ho používam tu? emit má totiž niekoľko výhod. Je napríklad možné písať inštrukcie do {} takto. emit { const.pri 5 const.alt 5 add stor.pri r } Vďaka tomu nemusíte neustále písať emit. Ďalej bežný emit "vracia" hodnotu uloženú v pri, takže môžete napísať: new a = emit const.pri 4; printf("%i, %i", a, emit const.pri 7); // 4, 7 A taktiež umožnuje písať inštrukcie oddelené čiarkou do () takto: printf("%i", emit(const.pri 2, const.alt 4, add)); // 6 Toto vám umožní oveľa lahšie integrovať emit so svojim kódom. Taktiež to umožnuje používať emit v Makrách cez #define. Nakoniec emit narozdiel od #emit robí určité kontroly pri kompilácii. Ak napríklad dáte lokálnu premennú do LOAD.pri, tak vám napíše error. To je hlavný dôvod, prečo som zvolil operátor emit pre tento tutoriál miesto #emit. Ak však nepotrebujete žiadnu z týchto výhod, všetko v tomto tutoriály sa dá použiť taktiež s #emit. 7. Záver V ďalšom diely tohto tutoriálu sa vrhneme na funkcie a lokálne premenné, taktiež si povieme viac o stacku.
  12. xhunterx

    Zneužitie PHP scriptu

    Skusil si ine pripony pre php, ako napr .phtml?
  13. xhunterx

    pomoc SSH příkaz.

    Do prikazu sed mozes dat regex, ktory ti to nahradi. https://www.google.sk/amp/s/www.cyberciti.biz/faq/how-to-use-sed-to-find-and-replace-text-in-files-in-linux-unix-shell/amp/
  14. xhunterx

    pomoc Existuje?

    Co takto fexists lol?
  15. xhunterx

    návod Hunterov úvod do bezpečnej komunikácie

    Presne ako tanga hovori. Aj XMPP servery maju prisluby ze nebudu ukladat spravy, ale to rovno do sprav na zaciatok mozes napisat: "Pls necitajte admini." a je to asi rovnako efektivne. XMPP som zvolil oproti IRC lebo aj ked mozno neni orientovane na komunitu, tak chatove skupiny podporuje a hlavne ich umoznuje sifrovat (ak su uzavrete, ak su otvorene to nema zmysel).
×