Flags auswerten mit Bitmasken - Verständnisfrage

  • Verständnisfrage.


    Es gibt verschiedene Funktionen, die Zweier-Potenzen als Flags verwenden (heißt das so?), also 1, 2, 4, 8, 16, 32, ... Ein berühmter Vertreter dafür ist die MsgBox, die eine beachtliche Anzahl von Flags benutzt.


    In diesem Thread möchte ich die Shift-States der Tastatur betrachten, die die Flags 1, 2, 4, 8, 16 und 32 benutzen. Auswerten kann man sie z.B. so:


    Beispiel 1


    Beispiel 2


    Meine Frage ist, was sind die praktischen Unterschiede? Für welchen Anwendungsfall ist die eine besser geeignet, als die andere? Oder ist am Ende alles gleich? :/

  • Oder ist am Ende alles gleich?

    Kommt darauf an, welche Unterschiede du meinst.
    Bei der Programmlogik unterscheiden sie sich schon massiv, denn beim zweiten Beispiel wird unsinnigerweise ne Schleife verwendet und damit jedes einzelne BitAnd dort 7x aufgerufen anstatt nur einmal wie es ausreichend wäre. Ich vermute einfach die Schleife kam nur deshalb mit rein weil der Autor auf Biegen und Brechen Switch-Case verwendne wollte und noch nie was von ContinueCase gehört hat. Die zweite Variante ist also massiv ineffizient. Und obendrauf wird auch noch ein Switch-Case ohne Auswertung der Expression verwendet anstatt einem Select-Case.


    Wie die Abfrage der Bits dann exakt mit BitAnd geschieht sieht dann erst einmal anders aus ist von der Rechnung her aber auch exakt das gleiche


    Beim ersten Beispiel passiert folgendes wenn das Flag (also hier das 4. Bit) gesetzt ist:

    If BitAND(0xFFFF, 8) Then wird aufgelöst zu If 8 Then und durch die implizite Konvertierung in Bool wird daraus (da 8 zu true gecastet wird) If True Then


    Wenn das Flag nicht gesetzt ist passiert folgendes:

    If BitAND(0x0, 8) Then --> If 0 Then --> If False Then


    Im Zweiten Beispiel wird es folgendermaßen schrittweise ausgewertet:

    Case BitAND(0xFFFF, 2 ^ 3) --> Case BitAND(0xFFFF, 8) --> Case 8 --> Case True


    Und für den Fall, dass das 4. Bit nicht gesetzt ist:

    Case BitAND(0x0, 2 ^ 3) --> Case BitAND(0x0, 8) --> Case 0 --> Case False

  • Soweit verstehe ich deine Erklärungen, bis auf die Stellen wo du 0xFFFF eingesetzt hast. Was hat es damit auf sich?


    Ansonsten schonmal Danke für die Erläuterungen, dass da wohl praktisch kein Unterschied ist (abgesehen von der Effizienz). Somit favorisiere ich die Möglichkeit im ersten Beispiel, oder gibt es noch eine galanterere? (ohne RegExen) :P

  • Hier noch 2 Schleifen-Variationen. Das Ergebnis könnte man mit "StringSplit()" auswerten. Ist zwar alles recht schön, aber einen praktischen Unterschied kann ich nicht erkennen. Sieht nach Geschmacksache aus. :saint:



    Edit: If $_iFlag = 0 Then Return '0' eingefügt.

  • 0xFFFF ist nur ein fiktives Beispiel bei dem das 4. Bit gesetzt ist. Brauchte halt nur irgendeinen knackigen Wert wo das BitAnd(..., 8) anschlägt.
    Das ist ja der eigentliche Sinn der Nummer hier - ein Konglomerat mehrerer Bits soll auf ganz bestimmte einzelne Bits hin überprüft werden.
    BitAnd macht hier quasi nichts anderes, als dass es einzelne Bits herausschält.

    Somit favorisiere ich die Möglichkeit im ersten Beispiel, oder gibt es noch eine galanterere? (ohne RegExen)

    Was genau stört dich an der If-Then-Konstruktion?
    Bei der ist ziemlich schnell klar was passieren soll und daher weiß ich nicht warum überhaupt jemand auf die Schnapsidee mit dem Switch innerhalb einer Schleife kam.


    Einen Einsatzzweck für Select-Case sehe ich hier auch nicht, da ja immer alle Fälle geprüft werden sollen und nicht (was der Vorteil vom Select wäre) vorher aufgehört werden soll wenn ein Fall zutraf.


    Klar kann man sich noch wilde Konstrukte ausdenken aber ich sehe keinen Anhaltspunkt inwiefern Verbesserungen zur If-Then-Konstruktion erzielt werden könnten.

    Man könnte minmal Zeichen einsparen wenn man es so schreibt, aber auch hier leidet wieder die Klarheit im Vergleich zu If-Then:

    Code
    $sRet = $_iFlag = 0 ? '0 [""]' : _
    (BitAND($_iFlag, 1 ) ? " 1, 'Either SHIFT key is pressed.' " : '') & _
    (BitAND($_iFlag, 2 ) ? " 2, 'Either CTRL key is pressed.' " : '') & _
    (BitAND($_iFlag, 4 ) ? " 4, 'Either ALT key is pressed.' " : '') & _
    (BitAND($_iFlag, 8 ) ? " 8, 'The Hankaku key is pressed' " : '') & _
    (BitAND($_iFlag, 16 ) ? " 16, 'Reserved (defined by the keyboard layout driver).' " : '') & _
    (BitAND($_iFlag, 32 ) ? " 32, 'Reserved (defined by the keyboard layout driver).' " : '')


    Hier noch 2 Schleifen-Variationen.

    Die im Grunde aber etwas völlig anderes machen. Bei deinem letzten Beispiel kann man ja leicht dynamisieren, da ja nur das BitAnd-Ergebnis ausgegeben werden soll.
    Bei deinen Beispielen oben jedoch verknüpfst du diese noch mit statischen Informationen (dem jeweiligen Text dahinter). Dort kommst du also um eine explizite Fallunterscheidung nicht drumherum.

  • Was genau stört dich an der If-Then-Konstruktion?

    Mich stört daran eigentlich gar nichts. Es ist nur ein (antrainiertes?) Gefühl, mehrere If-Abfragen mithilfe einer Schleife zu rationalisieren. Wie du siehst, habe ich diese Möglichkeit favorisiert. Ich habe auch schon gedacht, dass man damit seinen Code recht einfach erweitern kann, wenn man aus den einzeiligen If-Abfragen If-EndIf-Blöcke macht. Dann kann man gleich an Ort und Stelle einfügen, ob man nur Zahlen als Rückgabe haben will, oder wie es im Moment ist mit Text dahinter, oder gleich eine Aktion ausführen, usw.


    Vorallem finde ich, genau wie du geschrieben hast, dass damit sehr klar ist, was passieren soll.


    0xFFFF ist nur ein fiktives Beispiel bei dem das 4. Bit gesetzt ist. Brauchte halt nur irgendeinen knackigen Wert wo das BitAnd(..., 8) anschlägt.

    Verstanden!


    Uff! Dadurch ist jetzt altes, verschüttetes Wissen entschüttet worden und ich kann mich wieder erinnern, warum man Flags als Zweierpotenzen anlegt. Denn 0xFFFF würde den Christbaum ganz schön zum leuchten bringen. ;)

  • Hier noch eine Schleifen-Variante: