#pragma & #emit

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Guten Morgen,


    auf Wunsch einiger werde ich jetzt nochmal genauer in die Welt der Directives eintauchen, dieses Tutorial ist jetzt eher nichts mehr für Anfänger.
    In dem anderen Thread wurde auch angesprochen, ich sollte was zu dem Compiler sagen, wie er das verarbeitet. Aber dazu gibt es meiner Meinung nach nicht so viel zu sagen er verarbeitet die Directives vor allem anderen, weil es der "Hard Code" ist und daher sind diese Directives auch sehr statisch.


    #pragma
    Dieses #pragma kann die .amx Datei verändern, wenn man mit #pragma oder #emit arbeitet nennt man dies auch meistens amx-scripting.
    Ich mache mal eine kurze Erklärung für die wichtigsten Verwendungen für #pragma ;)
    Fangen wir an:
    #pragma deprecated
    Aber was macht das und was soll das bringen ?!
    Hier mal ein kleines Szenaro:
    new var = 5;
    #pragma deprecated var
    main(){
    printf("Wert: %d",var);
    }
    Dann erhalten wir einen Warning:
    Das passiert weil wir die Variable var nach dem #pragma deprecated unbrauchbar gemacht wird.
    Was es bringt:

    Code
    This is mostly useful for functions to preserve backwards compatability while updating the API.


    Nun zu der Nächsten Funktion:
    #pragma dynamic
    Dies sollte man nur nutzen, wenn der Memory Speicher voll ist, dann kommt meist so eine Warnung:

    Code
    Header size:            112 bytesCode size:               88 bytesData size:              200 bytesStack/heap size:      16384 bytes; estimated max. usage=6456 cells (25824 bytes)Total requirements:   16784 bytes


    Dies passiert bei den meisten GF's, weil dort zu viele Locale Variablen einen zu großen Array besitzen.
    Dort könnte man dann ein #pragma dynamic reinsetzen, das würde dann so aussehen:
    #pragma dynamic 25824
    und diese Warning Tabelle da oben würde verschwinden :)


    Als nächstes hätten wir noch solche Sachen:
    #pragma tabsize
    Jeder kennt diese Fehlermeldung:
    Sie entstehen, wenn man einen Codeschnipsel falsch einrückt.
    Man nutzt zum einrücken immer den Tabulator, doch meistens machen das viele Anfänger nicht und für die ist dieses #pragma eine Goldgrube, da dieses Directive in der .amx-Datei die tabsize = tablänge / größe automatisch einrückt.
    Es ist am besten das zu verwenden:
    #pragma tabsize 0
    Dann wird die Länge von den Tabs auf 0 gesetzt und alles ist in der .amx Datei eingerückt und der Compiler zeigt keine Warnings mehr (hier erkennt man, dass die pre-processoren vor dem "Rest Code" compiliert werden und dann erst die Erros/Warnings angezeigt werden !).


    Da gibt es noch eine weitere Funktion, mit der man Pawn ganz anders wird:
    #pragma semicolon
    Diese Funktion ermöglicht es in Pawn ohne ' ; ' zu arbeiten !
    Hier mal ein Beispiel:
    #pragma semicolon 0
    new var
    var = 5
    printf("Var: %d",var)
    return 1
    Dies würde ohne Errors funktionieren :) (Nicht sehr zu empfehlen, da es schnell zur Unübersichtlichkeit führt !


    Nun gehen wir mit #pragma langsam zum Ende:
    Zunächst:
    #pragma unused
    Dieses Directive ist ähnlich wie stock. Nur man kann nicht immer stock nutzen und da wo man stock nicht nutzen kann, benutzt man #pragma unused.
    Wir nehmen mal folgendes Szenario:
    public OnGameModeInit() {
    //Haha mir ist so langweilig ich mach eine variable die ich nicht nutze
    new var;
    return 1;
    }
    Da kommt folgender Warnig:
    Da können wir nämlich kein stock nutzen, da es eine lokale Variable ist und deshalb nutzen wir #pragma, das sähe dann so aus:
    public OnGameModeInit() {
    //Haha mir ist so langweilig ich mach eine variable die ich nicht nutze
    new var;
    #pragma unused var
    return 1;
    }
    und der Warning ist weg. :)


    PS: Es gibt noch viel viel mehr Funktionen mit #pragma aber die die am meisten verwendet werden sind diese.


    #emit
    So nun zu dem Nächsten und kompliziertesten Directive !
    Fangen wir mal einfach an:
    new var=5;
    #emit LOAD.S.pri var
    #emit ADD

    Code
    ".S"  steht für "stack" "pri" steht für "primary register""ADD" schreibt das Ergebnis in den primary register


    So würde #emit aber noch keinen Sinn machen :D
    Ich zeige mal ein Rechenbeispiel:
    new a = 2,
    b = 5,
    c = 0;
    #emit LOAD.S.pri a //Lädt a in den "primary register"
    #emit LOAD.S.alt b //Lädt b in den "alternate register"
    #emit ADD //addiert die zahlen und lädt das Ergebnis in den primary register
    #emit STOR.S.pri c //Kopiert das Ergebnis aus dem primary register in c
    c hätte also am Ende einen Wert von 7 !
    PS: Dies funktioniert nur auf Lokaler Ebene nicht auf Globaler !
    Wir können Variablen auch einen direkten Wert mit #emit geben, sähe dann so aus:
    new var;
    #emit CONST.pri 2
    #emit STOR.S.pri var
    var hätte jetzt den Wert 2.
    Natürlich können wir auch negative Werte erstellen:
    new var;
    #emit CONST.pri 2
    #emit NEG
    #emit STOR.S.pri var
    var hätte jetzt den Wert -2 !


    So das war eine kleine Einführung mit Integern, ich zeige mal was zu Strings/Arrays:
    new str[2][4] = {
    {'W', 'a', 's', '?'},
    {'\0', 'H', 'i', '\0'}
    };
    #emit CONST.pri str //gibt die addresse vom start des arrays
    #emit ADD.C 4 //Hier der pointer in die 2. Zeile
    #emit MOVE.alt //zwischen speicher im alternate register
    #emit LOAD.I //Lädt die daten .I = indirect
    #emit ADD.C 4//Hier pointer für das ende der 2. Zeile
    #emit STOR.I //speichert es indirekt
    printf("%s", str[0]); //printet: "Was?"
    printf("%s", str[1]); //printet: "Hi"
    So, das war eine ganz kurze Einführung in #emit, dieser Directive ist noch weit aus komplizierter wie ich ihn hier dargestellt habe, für eine 100% genaue Definition, bitte hier klicken: http://forum.sa-mp.com/showthread.php?t=315531 //von Y_LESS


    Zu meinem 1. Tutorial über Makros: [ SCRIPTING ] Directives / Makros (pre-processor)


    Ich hoffe die Mühe hat sich gelohnt euch so ein bisschen zu informieren, bitte ein Feedback :)


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

    Einmal editiert, zuletzt von Kaliber ()

  • Erstmal danke für das Minitutorial. :)


    Wozu dient aber #emit? Also welchen Vorteil gegenüber normalen Rechenoperationen, ... bringt es mit sich (ohne, dass ich jetzt in den Thread von Y_Less schauen muss)?

    Ich bin Dittis Signatur.

  • Erstmal danke für das Minitutorial.


    Naja, diese Erklärung über #pragma und #emit ist länger als so manch andere Tutorial die ich hier im Forum gesehen habe :S


    Wozu dient aber #emit? Also welchen Vorteil gegenüber normalen Rechenoperationen, ... bringt es mit sich (ohne, dass ich jetzt in den Thread von Y_Less schauen muss)?


    #emit ist schneller und da es amx-Scripting ist, verbraucht es 1000x weniger Speicherplatz in der .amx Datei als der Rest ^^ Somit kann man wenn man viel mit #emit macht seine .amx Datei auf ein minimum komprimieren ;)


    Ganz nett. Eine Frage, gibst du all deinen Threads sofort 5 Sterne?


    Nicht wirklich :wacko:
    //Edit:

    Variablen unverwendbar machen oder wie auch immer ich das nennen soll.
    Es gibt ja schon 2 einfache Methoden


    Oh, ja da hätte ich etwas konkreter werden sollen.
    Ja, es gibt auch Parameter von Funktionen die du nicht weglassen kannst, sprich sowas:
    ocmd:Test(playerid, params[])
    {
    return SendClientMessage(playerid,rot,"hi");
    }
    und dort wäre ein
    #pragma unused params
    angebracht ;)


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

  • Wieso nutzt du nicht deine eigenen Beispiele?
    Wieso klaust du sie von Y_Less? (http://forum.sa-mp.com/showthread.php?t=315531)


    Ich glaub du verstehst selbst nicht was emit wirklich alles kann.


    Mach mal deine Augen auf, bevor du mir sowas unterstellst, ich habe Y_LESS seinen Beitrag als Grundlage genommen, weil er der einzige ist, der das jemals erklärt hat du Held :whistling:
    Außerdem sind das eigentlich alles meine Beispiele :pinch:


    mfg. :thumbdown:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

  • mal so eine frage hast du ein speedtest mal gemacht zwischen zwei selben Funktion wobei eine nur auf emit basiert.


    Ich geh davon aus das sowas beim kompilen schneller ist da bei normalen funktionen beziehungsweise verwendung(skripting) das ganze erstmal in die pcodes umgewandelt werden muss.
    Jedoch im endeffekt ist das ganze nach dem compilen das selbe.


    Also ich wäre mit der behauptung erstmal vorsichtig was schneller ist oder weniger speicherplatz benötigt.
    Daher frag ich mich woher du die 1000 mal nimmst hast du da paar beweise.

  • mal so eine frage hast du ein speedtest mal gemacht zwischen zwei selben Funktion wobei eine nur auf emit basiert.


    Ich geh davon aus das sowas beim kompilen schneller ist da bei normalen funktionen beziehungsweise verwendung(skripting) das ganze erstmal in die pcodes umgewandelt werden muss.
    Jedoch im endeffekt ist das ganze nach dem compilen das selbe.


    Also ich wäre mit der behauptung erstmal vorsichtig was schneller ist oder weniger speicherplatz benötigt.
    Daher frag ich mich woher du die 1000 mal nimmst hast du da paar beweise.


    Ja die habe ich ;)


    Hier das Ergebnis eines Speedtestes:



    //edit:
    2. Ergebnis:



    und hier der Speedtest:



    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

    Einmal editiert, zuletzt von Kaliber ()

  • Kleine Wortkorrektur.
    Mit #pragma depracted machst du ein Symbol NICHT unbrauchbar. Du markierst es lediglich als veraltet und weist somit daraufhin, dass es eine bessere Möglichkeit gibt. Funktionieren tut das Symbol trotzdem noch.
    Und was hat #pragma unused mit einem stock zu tun?
    Das Einzige, was es da gibt, ist, dass man, indem man die Variable in einem Stock verwendet, nicht mehr unbenutzt ist.

  • Und was hat #pragma unused mit einem stock zu tun?


    Nichts, das habe ich auch nie gesagt, das die was mit einander zu tun haben, nur das sie eine Ähnlichkeit besitzen:
    //auf globaler Ebene
    new stock val;


    //auf lokaler ebene
    new var;
    #pragma unused var
    Beides ergibt keinen Warning :rolleyes:


    mfg. :thumbup:


    //Edit:


    So und ich habe mal einen Speichertest gemacht :)


    Das Resultat:


    Die .amx Datei bei normal: 5kb
    Die .amx Datei mit emit: 2kb


    Die Scripts:
    Pastebin (Für emit)
    Pastebin (Für normal)


    //Edit²:
    Habe das ganze mit 4x so vielen Variablen oben getestet Resultat:


    Die .amx Datei bei normal: 20kb
    Die .amx Datei bei emit: 8kb


    Also es macht schon was aus, wenn man viele Variablen verwendet ^^


    Also nicht 1000x besser, aber ein bisschen :)


    mfg. :thumbup:

    ast2ufdyxkb1.png


    Leute, lernt scripten und versucht mal lieber etwas selber zu schreiben, als es aus einem GF zu kopieren. :S

    2 Mal editiert, zuletzt von Kaliber ()

  • ok ich ziehe meine Aussage zurück.
    Wie ich herraus gefundne habe wird der Heapspace damit exdrückt daher sind die codes schneller
    und einzelne Opcodes ersetzen zwei oder mehrere so genannte "plain"(Ebenen) Opecodes. Daher sinkt auch die .amx größe

    Einmal editiert, zuletzt von IPrototypeI ()

  • Hab das Tutorial erst jetzt gesehen


    Kaliber
    Sorry, aber das ist jetzt eine Sache, in der muss ich dir komplett widersprechen: #emit dient nicht direkt dazu, die Geschwindigkeit zu zu steigern (Sprich es ist eben nicht für Optimierung gedacht). Nun wofür "darf" man jetzt #emit verwenden. Du hast eine abstrahierte VM am laufen, welche nativen Bytecode ausführt (Jedoch noch ohne SYSREQ.D/SYSREQ.ND Befehle). Du hast damit die Möglichkeit, direkt auf eine VM zuzugreifen.


    #emit sollte in der Regel schneller sein als eine implementierte Funktion - das sollte aber verständlich sein, ich hab mir aber noch nie den nativen Bytecode angeschaut, sprich weiss nicht, wie der emit Code generiert und eingebunden wird (Wenn aber schon Inline Assembler so schrecklich generiert wird, hege ich da keine zu grossen Hoffnungen). Schau dir mal die Implementierung der Pawn Sprache im SDK an (Backend), dann sollte dir klar werden, dass #emit nicht zur Optimierung dient (Ausser man ist so braindamaged und ist arbeitslos und will seinen GM per #emit schreiben)....


    Wie gesagt, eigene Beispiele wie das Aufrufen von Funktionen und verwenden von Rückgabewerten wären nett, sonst kann man sowas nicht wirklich Tutorial nennen, eher Kurzzusammenfassung von Wissen ;)


    Edit: Und WAS genau #pragma dynamic in der VM bewirkt, erklärste auch nicht - Du betreibst oberflächliche Fehlerbehandlung


  • Du vergleichst ja auch zwei verschiedene codes und verwendest die default-compiler optionen, welche nicht so eingestellt sind, dass moeglichst wenig informationen/codes gespeichert werden.
    In dem normalen code setzt du a und b andauernd auf 1. In dem #emit code aber nicht.
    public OnGameModeInit()
    {
    new time = GetTickCount(), a,b,c;
    for(new i; i<6; i++)
    {
    c = (a+b);
    c = (a+b);
    ...
    Wenn dieser code mit dem debugging level 0 kompiliert wird (pawncc -d0 src.pwn, oder in pawno "-d0" zu den parametern unter "Run options" hinzufuegen), dann ist die resultierende amx datei sogar circa 10 byte kleiner.