• Offizieller Beitrag

    Diese kleine UDF enthält 8 Funktionen (BitAND, BitOR, BitNOT, BitROL, BitROR, BitSHL, BitSHR, BitXOR) zum bearbeiten von Integerzahlen im 64-Bit-Format.

    Das sind 8 Assembler-Funktionen, die da aufgerufen werden. Das AutoIt-Script muss aber im 64-Bit-Modus laufen (siehe Example).

    Edit 26.12.2018: Neue Version

    - Bei AND, OR und XOR können nun bis zu 8 Parameter direkt im Funktionsaufruf übergeben werden. Wer mehr Parameter benötigt, muss sie als Array in Parameter Eins übergeben. Danke, Bitnugger!

    - Es gibt jetzt noch zwei Hilfsfunktionen "_BitRotate64" und "_BitShift64" in Anlehnung an die originalen Funktionen. Allerdings einheitlich (im Gegensatz zu den originalen Funktionen): mit negativen Werten nach links und positiven Werten nach rechts.

    Edit 27.12.2018: Neue Version

    - OnAutoItExitRegister erst nach der Deklaration der globalen Variablen.

    - Die Anforderung des Speichers geschieht jetzt in einer Funktion: "__BitOp64OnStart".

    - Fehler behoben bei "_BitRotate64" und "_BitShift64", wenn 0 für Rotate oder Shift übergeben wurde.

    - Fehler behoben bei "_BitROx64" und "_BitSHx64". Der Parameter-Aufruf war falsch rum. :huh:

    - Das Beispiel-Script komplett überarbeitet und aufgeräumt.

    • Offizieller Beitrag

    Bitnugger hatte bemängelt, dass die UDF bei AND, OR und XOR nur zwei Parameter zulässt. Aber anstatt alle 64-Bit-Zahlen in den Funktionsaufruf zu packen, finde ich es praktischer ein Array mit den Werten zu übergeben.

    Außerdem ist es nicht angebracht, die Assemblerfunktion x-mal aufzurufen (die DllCallAdress-Aufrufe kosten Zeit). Lieber alle Werte in eine Struktur packen, den Pointer übergeben (sowie die Anzahl) und den Rest von Assembler aus erledigen.

    Ich habe die Funktionen mal angepasst (siehe Post #1).

  • Bitnugger hatte bemängelt, dass die UDF bei AND, OR und XOR nur zwei Parameter zulässt. Aber anstatt alle 64-Bit-Zahlen in den Funktionsaufruf zu packen, finde ich es praktischer ein Array mit den Werten zu übergeben.

    Außerdem ist es nicht angebracht, die Assemblerfunktion x-mal aufzurufen (die DllCallAdress-Aufrufe kosten Zeit). Lieber alle Werte in eine Struktur packen, den Pointer übergeben (sowie die Anzahl) und den Rest von Assembler aus erledigen.

    Sehr schön... doch ein paar mehr als zwei Parameter sollten es meiner Meinung nach doch schon sein, bevor ich "genötigt" bin, vor dem Funktionsaufruf ein Array zu definieren. ;)

    Hier als Bsp. bei _BitAND64 (mit max. 8 Parametern), wie ich mir das gedacht habe...

  • Sehr schön :)

    Mir ist noch ein "Schönheitsfehler" aufgefallen, das OnAutoItExitRegister sollte erst nach _MemVirtualAlloc ausgeführt werden, da sonst (zumindest theoretisch) die Möglichkeit besteht, dass _MemVirtualFree aufgerufen wird bevor überhaupt Speicher reserviert wurde. Wird wahrscheinlich niemals auftreten, aber irgendwie verursacht diese Reihenfolge einen Knoten in meinem Hirn :D

    lg

    M

  • Ok, das macht Sinn!

    Ich hab's aber noch etwas anders gelöst (ohne Eval).

    Soso, du magst Eval also nicht... so sah auch meine erste Lösung aus... mir hatte es aber nicht gefallen, nur zum Befüllen der Struktur ein Array zu erzeugen. Deshalb tendiere ich eher zu Eval. Unterm Strich aber völlig egal, weil ja beides funktioniert. Oder?

    Eine Sache solltest du dir aber unbedingt abgewöhnen... For...Next-Schleifen im globalen Kontext!

    Denn dadurch machst du die Count-Variable $i zu einer globalen Variable, was nicht nur unschön ist, sondern später auch mächtig Ärger machen kann, weil man innerhalb von Funktionen davon ausgeht, dass solche Lauf-Variablen eben nicht global sind.

    Hier ein Beispiel:

    Mir ist noch ein "Schönheitsfehler" aufgefallen, das OnAutoItExitRegister sollte erst nach _MemVirtualAlloc ausgeführt werden, da sonst (zumindest theoretisch) die Möglichkeit besteht, dass _MemVirtualFree aufgerufen wird bevor überhaupt Speicher reserviert wurde.

    Ja, ok, das ist aber in der Tat nur ein Schönheitsfehler, denn er überprüft doch die Werte in dem Array, bevor _MemVirtualFree aufgerufen wird...

    If $__g_pBitOpASMCode[$i] > 0 Then _MemVirtualFree($__g_pBitOpASMCode[$i], $__g_iBitOpMemSize[$i], $MEM_DECOMMIT)

  • Eine Sache solltest du dir aber unbedingt abgewöhnen... For...Next-Schleifen im globalen Kontext!

    Um diese Uhrzeit sollte ich vielleicht keine Fragen mehr stellen, aber was soll's ^^:

    Die Laufvariable in einer For...Next-Schleife ist ja nicht deklarationspflichtig bzw. gilt automatisch als deklariert, selbst bei Opt('MustDeclareVars', 1) .

    (ich vermute mal, das war ursprünglich ein Bequemlichkeitsfeature, oder ? )

    Man könnte die angesprochene Gefahr bannen, indem man eine passende Notation wählt, also z.B. :

    Global $__g_Counter

    Sollte man im globalen Teil eines Skriptes, welches als Include dienen soll, aber überhaupt Schleifen oder sonstigen Code schreiben ? Wenn ich die Standardincludes betrachte, sehe ich dort nur Deklarationen von globalen Variablen, Konstanten, Enums usw. und natürlich die Funktionen.

    Hätte Oscar in seiner BitOperations64.au3 den Teil :

    Code
    ; Allocate memory for the Assembler-Code
    For $i = 0 To UBound($__g_dBitOpASMBin) - 1
        $__g_iBitOpMemSize[$i] = StringLen($__g_dBitOpASMBin[$i]) / 2 - 1
        $__g_pBitOpASMCode[$i] = _MemVirtualAlloc(0, $__g_iBitOpMemSize[$i], $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
        If $__g_pBitOpASMCode[$i] = 0 Then Exit MsgBox(16, 'BitOpASM-Error!', "Can't allocate virtual memory!")
        $__g_tBitOpASMCode[$i] = DllStructCreate('byte[' & $__g_iBitOpMemSize[$i] & ']', $__g_pBitOpASMCode[$i])
        DllStructSetData($__g_tBitOpASMCode[$i], 1, $__g_dBitOpASMBin[$i])
    Next

    in eine Funktion gepackt, wäre doch alles ok, oder ?

    Ich hoffe, Du verstehst was ich meine - ich bin mir da momentan nicht mehr sicher 8o.

    Gruß Musashi

    86598-musashi-c64-png

    "Am Anfang wurde das Universum erschaffen. Das machte viele Leute sehr wütend und wurde allenthalben als Schritt in die falsche Richtung angesehen."

  • (ich vermute mal, das war ursprünglich ein Bequemlichkeitsfeature, oder ? )

    Ja, könnte man so nennen... und ist es immer noch...

    in eine Funktion gepackt, wäre doch alles ok, oder ?

    Ja, dann wäre alles klar!

    Ich verwende dafür immer die Funktion _Main(), die es bei mir so gut wie immer gibt, damit solche Sachen nicht passieren.

    • Offizieller Beitrag

    das OnAutoItExitRegister sollte erst nach _MemVirtualAlloc ausgeführt werden, da sonst (zumindest theoretisch) die Möglichkeit besteht, dass _MemVirtualFree aufgerufen wird bevor überhaupt Speicher reserviert wurde.

    Nein, das sollte man nach Möglichkeit nicht tun, jedenfalls nicht, wenn man mehrfach Speicher anfordert. Denn, wenn eine Anforderung fehlschlägt und das Programm deswegen beendet wird, wird der restliche (vorher angeforderte Speicher) nicht mehr freigegeben.

    Deswegen habe ich ja die Abfrage auf "0" eingefügt. So wird nur der Speicher freigegeben, der auch vorher erfolgreich angefordert wurde.

    Aber Du hast insofern recht, dass das OnAutoItExitRegister erst nach der Deklaration der Variablen stehen sollte, sonst meckert AutoIt, dass die Variablen noch nicht deklariert sind.


    Eine Sache solltest du dir aber unbedingt abgewöhnen... For...Next-Schleifen im globalen Kontext!

    Ja, schuldig im Sinne der Anklage!

    Bei UDFs sollte man besonders auf sowas achten. Aber generell die Funktion "_Main" dafür zu verwenden, ist auch nicht gut.

    Wenn Du das in mehreren UDFs machst, hast Du das Problem, dass es die Funktion doppelt gibt.

    Ich habe die "Mainfunktion" bei mir jetzt mal "__BitOp64OnStart" genannnt.

  • Aber generell die Funktion "_Main" dafür zu verwenden, ist auch nicht gut.

    Wenn Du das in mehreren UDFs machst, hast Du das Problem, dass es die Funktion doppelt gibt.

    Selbstverständlich würde ich _Main() nicht in einer UDF verwenden, sondern nur in "normalen" Scripten und da ist das auch völlig ok.

    Im Übrigen ist das OnAutoItExitRegister bzw. das If $__g_pBitOpASMCode[$i] > 0 Then wohl nicht zwingend nötig, da _MemVirtualFree($__g_pBitOpASMCode[$i], $__g_iBitOpMemSize[$i], $MEM_DECOMMIT) dann einfach ein False liefert, wenn $__g_pBitOpASMCode[$i] = "" ist. Konnte der Speicher freigegeben werden, liefert es True.... das allerdings traurigerweise auch, wenn man denselben Speicher mehrmals hintereinander freigibt.

  • In der Funktion _BitRotate64() hat sich ein Fehler eingeschlichen... denn wenn $iRotate = 0 ist, musst du $iValue1 und nicht $iRet zurückgeben!

    Ich würde es so machen:

    Code
    ; A helper-function for "_BitROL64" and "_BitROR64"
    ; $iRotate = Number of bits to rotate to the right (negative numbers rotate left).
    Func _BitRotate64($iValue1, $iRotate = 1)
        Return $iRotate = 0 ? $iValue1 : $iRotate > 0 ? _BitROR64($iValue1, $iRotate) : _BitROL64($iValue1, $iRotate)
    EndFunc   ;==>_BitRotate64
  • In deinem aktuellen Example hast du für _BitAND64/_BitOR64/_BitXOR64 jetzt übrigens keine Beispiele mehr, die zeigen, wie es mit einem Array geht... die waren vorher drin und ich würde sie auch wieder hinzufügen. ;)

    • Offizieller Beitrag

    jetzt übrigens keine Beispiele mehr, die zeigen, wie es mit einem Array geht... die waren vorher drin und ich würde sie auch wieder hinzufügen.

    Oh mann! Ich bin heute echt nicht voll da! :whistling:

    Da war auch noch ein Fehler in den Funktionen zum rotieren/shiften. Der Parameteraufruf war falsch rum.

    Alles ausgebessert und das Beispiel-Script komplett überarbeitet und aufgeräumt (siehe Post#1).