vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
Zippen wie die Profis!  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2024
 
zurück
Rubrik: Variablen/Strings · Algorithmen/Mathematik   |   VB-Versionen: VB613.06.05
Abfragen, Setzen und Löschen von Bits

Funktionen zum Abfragen, Setzen und Löschen von Bits in Ganzzahl-Variablen

Autor:   Manfred BohnBewertung:     [ Jetzt bewerten ]Views:  28.530 
ohne HomepageSystem:  Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 Beispielprojekt auf CD 

In VB verwendet man den Zugriff auf Bits nur selten, z.B. bei der Belegung von 'Flag'-Variablen; aber selbst da gibt es die entsprechend benannten VB-Konstanten, durch die das richtige Bitmuster in den Flag-Parameter eintragen wird.

Insofern ist die Beschäftigung mit Bits für VB-Programmierer eher uninteressant. Trotzdem sollte man auch mit Bits umgehen können, weil sie die 'informationelle' Basis der Operationen bilden.

VB verfügt über bitweise arbeitende Operatoren (AND, EQV, IMP, OR). In Kombination mit dem NOT-Operator lassen sich die Bitmuster von zwei Variablen auf alle denkbaren Arten kombinieren. (Der XOR-Operator entspricht der Negation der EQV-Verknüpfung.)

Was es in VB aber nicht gibt, sind Funktionen, durch die man direkt einzelne Bits in einer Variable abfragen, setzen oder löschen kann.

Das Modul 'modBit' enthält deshalb die Funktion 'Ist_Bit_Gesetzt' zurAbfrage eines einzelnen Bits. Die Funktion 'Setze_Bit' setzt ein Bit und die Funktion 'Lösche_Bit' löscht ein Bit, falls es gesetzt ist. Dabei ist natürlich jeweils die Angabe der Position des Bit in der Variable erforderlich. Die Position 1 bezieht sich dabei auf das 'linke' Bit.

Das Modul unterstützt die internen ganzzahligen VB-Variablentypen BYTE (8 Bit), INTEGER (16 Bit), LONG (32 Bit) und den nur als Untertyp von VARIANT implementierten Datentyp DECIMAL (96 Bit).

Für 'Setze_Bit' und 'Lösche_Bit' gilt:
Die als Parameter übergebene Zahl bleibt unverändert. In der Funktionsrückgabe ist das entsprechende Bit gesetzt bzw. gelöscht.

Details:
Die Funktionen im Modul 'modBit' verwenden die Bit-Operatoren AND, OR, XOR und greifen auf Zweierpotenzen zurück.

Die Bit-Operatoren in VB unterstützen nur Werte im Geltungs-Bereich des VB-Datentyps LONG. Für den Zugriff auf das in der VARIANT-Variable enthaltene 96-Bit-Muster des Untertyps DECIMAL muss deshalb eine Byte-Kopie in einen geeigneten UDT durchgeführt werden.

Die dezimale Darstellung der VB-Datentypen ist gegenüber dem zugrundeliegenden binären Muster jeweils verschoben, damit INTEGER- und LONG-Variable auch negative Werte enthalten können. Aus diesem Grund sind datentypspezifische Hilfsfunktionen erstellt worden, die diese Transformationen berücksichtigen. Die Verschiebung beim Datentyp DECIMAL scheint technisch bedingt zu sein.

Von der Manipulation von Bits in Gleitkommazahlen (IEEE-Format) ist abzuraten, weil die einzelnen Bitpositionen spezifische Bedeutungen bei der Verarbeitung der binären Muster besitzen (Interpretation als Exponentialdarstellung). Nicht alle Bitmuster sind auch gültig und definiert. Es kann u.a. zu Überlauf-Fehlern kommen.

Variablen des Datentyps BOOLEAN sind 16 Bit lang. Bei der Belegung mit 'true' sind alle Bits gesetzt (entspricht als Integer: -1), bei der Belegung mit 'false' sind alle Bits gelöscht (entspricht als Integer: 0). Jede Zuweisung eines Integer-Wertes <> 0 auf eine boolsche Variable erzeugt den Wert 'true'. Die Manipulation von Bits in einer boolschen Variable ist deshalb nicht sinnvoll.

Anwendung:
Das Modul 'modBit' ist nützlich bei der Belegung von benutzerdefinierten Flag-Variablen. Durch Flags kann die Parameterliste einer Funktion, die auf eine Vielzahl von boolschen Einstellungen reagiert, kurz gehalten werden. Ein einziger LONG-Parameter kann 32 Einstellungen übergeben, ein VARIANT-Parameter als DECIMAL-Flag sogar 96. Im rufenden Programm kann durch 'Setze_Bit' / 'Lösche_Bit' die Einstellung (z.B. einer CheckBox oder eines Oprions-Buttons) in der Flag-Parameter-Variable eingetragen werden. In der gerufenen Prozedur (z.B. in einem Klassenmodul) kann durch 'Ist_Bit_Gesetzt' jede Einstellung abgefragt werden. Um dabei den Überblick nicht zu verlieren, sollte man eine Liste anlegen, aus der hervorgeht, welche Bitposition im Flag-Parameter sich auf welches Steuerelement (bzw. welchen Steuerelemente-Index) bezieht.

Angenommen, ein Formular enthält ein Checkbox-Steuerelementefeld 'chkParameter', das maximal 32 Elemente umfasst. Der folgende Code zeigt, wie die Einstellungen der Boxen in eine Flag-Variable (LONG) übertragen und abgefragt werden.

' ==================================================================
Dim i As Byte         ' Loop
Dim flags As Long     ' Flag-Variable (LONG)
Dim bs As String      ' Flag-String (Demo)
 
' Einstellungen in Flag-Variable eintragen
flags = 0  ' alle Flags sind gelöscht
For i = 0 To chkParameter.Count - 1
  If chkParameter(i).Value = vbChecked Then
    flags = Setze_Bit(flags, i + 1)
  End If
Next i
 
' Flag-Variable abfragen (z.B. in der gerufenen Prozedur)
bs = String(32, ".")
For i = 1 To 32
  If Ist_Bit_Gesetzt(flags, i) Then
    Mid$(bs, i, 1) = "1"
  End If
Next i
 
MsgBox "Flag-Variable: " + CStr(flags) + vbCrLf + bs
' =============================================================
' ============================================================
' Start Quellcode Modul: modBit
' ============================================================
 
Option Explicit
 
' Modul zum Abfragen, Setzen und Löschen von Bits
' in Variablen des Typs BYTE, INTEGER, LONG, Variant/DECIMAL
 
' Verwendung der Bit-Operatoren AND, OR, XOR
' und von 2-er Potenzen
 
' Übersicht über die Bit-Operatoren in VB
' =======================================
 
' Variable    Ergebnis log. Operator
' V1 V2       AND EQV IMP OR  XOR
' ----------------------------------
' 0  0         0   1   1   0   0
' 0  1         0   0   1   1   1
' 1  0         0   0   0   1   1
' 1  1         1   1   1   1   0
 
' Operator NOT kehrt Bit um
' V1 V2    NOT AND   NOT IMP   NOT OR
' -----------------------------------
' 0  0        1         0        1
' 0  1        1         0        0
' 1  0        1         1        0
' 1  1        0         0        0
 
' c = a XOR b    entspricht:  c = NOT (a EQV b)
 
 
' Für das Kopieren eines Decimal-Wertes in 3 Long-Werte
' (incl. Verwaltungsbytes)
Private Type Dec_Long
  Typ As Integer
  Nz As Byte
  Vz As Byte
  l(2 To 4) As Long
End Type
 
' Kopieren von Bytefolgen
' verwendet für das Kopieren eines Decimal-Wertes in 4 Long-Werte
Private Declare Sub CopyMemory Lib "kernel32" _
  Alias "RtlMoveMemory" ( _
  ByVal destination_pointer As Long, _
  ByVal source_pointer As Long, _
  ByVal bytes As Long)
Public Function Setze_Bit(ByVal arg As Variant, _
  ByVal bitpos As Byte) As Variant
 
  ' Bit an Position 'bitpos' der Variable 'arg' setzen,
  ' falls nicht gesetzt und Datentyp unterstützt
 
  If VarType(arg) = vbByte Then
    Setze_Bit = Setze_Bit_Byte(arg, bitpos)
  ElseIf VarType(arg) = vbInteger Then
    Setze_Bit = Setze_Bit_Integer(arg, bitpos)
  ElseIf VarType(arg) = vbLong Then
    Setze_Bit = Setze_Bit_Long(arg, bitpos)
  ElseIf VarType(arg) = vbDecimal Then
    Setze_Bit = OpBit_Decimal(arg, bitpos, 1)
  Else
    ' nicht unterstützter Typ
    ' ---> unveränderte Rückgabe
    Setze_Bit = arg
  End If
End Function
Public Function Lösche_Bit(ByVal arg As Variant, _
  ByVal bitpos As Byte) As Variant
 
  ' Bit an Position 'bitpos' der Variable 'arg' löschen,
  ' falls gesetzt und Datentyp unterstützt
 
  If VarType(arg) = vbByte Then
    Lösche_Bit = Lösche_Bit_Byte(arg, bitpos)
  ElseIf VarType(arg) = vbInteger Then
    Lösche_Bit = Lösche_Bit_Integer(arg, bitpos)
  ElseIf VarType(arg) = vbLong Then
    Lösche_Bit = Lösche_Bit_Long(arg, bitpos)
  ElseIf VarType(arg) = vbDecimal Then
    Lösche_Bit = OpBit_Decimal(arg, bitpos, 2)
  Else
    ' nicht unterstützter Typ
    ' ---> unveränderte Rückgabe
    Lösche_Bit = arg
  End If
End Function
Public Function Ist_Bit_Gesetzt(ByVal arg As Variant, _
  ByVal bitpos As Byte) As Boolean
 
  ' Bit an Position 'bitpos' der Variable 'arg' abfragen
  ' True: Bit ist gesetzt
  ' False: Bit nicht gesetzt oder falsche 'Bitpos'
 
  If VarType(arg) = vbByte Then
    Ist_Bit_Gesetzt = Ist_Bit_Gesetzt_Byte(arg, bitpos)
  ElseIf VarType(arg) = vbInteger Or VarType(arg) = vbBoolean Then
    Ist_Bit_Gesetzt = Ist_Bit_Gesetzt_Integer(arg, bitpos)
  ElseIf VarType(arg) = vbLong Then
    Ist_Bit_Gesetzt = Ist_Bit_Gesetzt_Long(arg, bitpos)
  ElseIf VarType(arg) = vbDecimal Then
    Ist_Bit_Gesetzt = OpBit_Decimal(arg, bitpos, 3)
  Else
    ' nicht unterstützter Typ
    ' ---> unveränderte Rückgabe
    Ist_Bit_Gesetzt = arg
  End If
End Function
Private Function Setze_Bit_Long(ByVal arg As Long, _
  ByVal bitpos As Byte) As Long
 
  ' Setzt ein Bit an eine Position in Long-Variable
  ' Bitposition: 1 --> 32    (von links nach rechts)
 
  Const h As Long = -2 ^ 31
 
  If bitpos > 32 Or bitpos < 1 Then
    Setze_Bit_Long = arg: Exit Function
  End If
 
  If bitpos = 32 Then
    arg = &H80000000 Or arg
  Else
    arg = (2 ^ (bitpos - 1)) Or arg
  End If
 
  Setze_Bit_Long = arg 
End Function
Private Function Lösche_Bit_Long(ByVal arg As Long, _
  ByVal bitpos As Byte) As Long
 
  ' Löscht ein Bit an einer Position in Long-Variable
  ' Bitposition: 1 --> 32    (von links nach rechts)
 
  Const h As Long = 2 ^ 31 - 1  ' 2147483647
 
  If bitpos > 32 Or bitpos < 1 Then
    Lösche_Bit_Long = arg: Exit Function
  End If
 
  If bitpos = 32 Then
   arg = h And arg
  Else
   arg = ((2 ^ (bitpos - 1)) Xor CLng(-1)) And arg
  End If
 
  Lösche_Bit_Long = arg  
End Function
Private Function Ist_Bit_Gesetzt_Long(ByVal arg As Long, _
  ByVal bitpos As Byte) As Boolean
 
  ' Gibt True zurück, falls ein bestimmtes Bit gesetzt ist
  ' Bitposition: 1 --> 32    (von links nach rechts)
 
  If bitpos > 32 Or bitpos < 1 Then Exit Function
  Ist_Bit_Gesetzt_Long = False
 
  If bitpos = 32 Then
    Ist_Bit_Gesetzt_Long = arg And &H80000000
  Else
    Ist_Bit_Gesetzt_Long = arg And (2 ^ (bitpos - 1))
  End If  
End Function
Private Function Setze_Bit_Integer(ByVal arg As Integer, _
  ByVal bitpos As Byte) As Integer
 
  ' Setzt ein Bit an eine Position in Integer-Variable
  ' Bitposition: 1 --> 16    (von links nach rechts)
 
  If bitpos > 16 Or bitpos < 1 Then
    Setze_Bit_Integer = arg: Exit Function
  End If
 
  If bitpos = 16 Then
    ' falls das höchste bit gesetzt wird,
    ' muß der Integer ins Negative gedreht werden
    If arg >= 0 Then arg = (-32768 + arg)
  Else
    arg = (2 ^ (bitpos - 1)) Or arg
 End If
 
  Setze_Bit_Integer = arg  
End Function
Private Function Lösche_Bit_Integer(ByVal arg As Integer, _
  ByVal bitpos As Byte) As Integer
 
  ' Löscht ein Bit an einer Position in Integer-Variable
  ' Bitposition: 1 --> 16    (von links nach rechts)
 
  If bitpos > 16 Or bitpos < 1 Then
    Lösche_Bit_Integer = arg: Exit Function
  End If
 
  If bitpos = 16 Then
   ' falls das höchste bit gelöscht wird,
   ' muß der Integer ins Positive gedreht werden
   If arg < 0 Then arg = 32768 + arg
  Else
   arg = ((2 ^ (bitpos - 1)) Xor CInt(-1)) And arg
  End If
 
  Lösche_Bit_Integer = arg  
End Function
Private Function Ist_Bit_Gesetzt_Integer(ByVal arg As Integer, _
  ByVal bitpos As Byte) As Boolean
 
  ' Gibt True zurück, falls ein bestimmtes Bit gesetzt ist
  ' in Integer-Variable
 
  If bitpos > 16 Or bitpos < 1 Then Exit Function
 
  If bitpos = 16 Then
    ' Das höchste Bit ist gesetzt, wenn der Integer negativ ist
    Ist_Bit_Gesetzt_Integer = arg < 0
  Else
    Ist_Bit_Gesetzt_Integer = arg And (2 ^ (bitpos - 1))
  End If  
End Function
Private Function Setze_Bit_Byte(ByVal arg As Byte, _
  ByVal bitpos As Byte) As Byte
 
  ' Setzt ein Bit an eine Position in Byte-Variable
  ' Bitposition: 1 --> 8    (von links nach rechts)
 
  If bitpos > 8 Or bitpos < 1 Then
    Setze_Bit_Byte = arg: Exit Function
  End If
 
  Setze_Bit_Byte = (2 ^ (bitpos - 1)) Or arg     
End Function
Private Function Lösche_Bit_Byte(ByVal arg As Byte, _
  ByVal bitpos As Byte) As Byte
 
  ' Löscht ein Bit an einer Position in Byte-Variable
  ' Bitposition: 1 --> 8    (von links nach rechts)
 
  If bitpos > 8 Or bitpos < 1 Then
    Lösche_Bit_Byte = arg: Exit Function
  End If
 
  Lösche_Bit_Byte = ((2 ^ (bitpos - 1)) Xor CInt(-1)) And arg 
End Function
Private Function Ist_Bit_Gesetzt_Byte(ByVal arg As Byte, _
  ByVal bitpos As Byte) As Boolean
 
  ' Gibt True zurück, falls ein bestimmtes Bit gesetzt ist
  ' in Byte-Variable
 
  If bitpos > 8 Or bitpos < 1 Then Exit Function
 
  Ist_Bit_Gesetzt_Byte = arg And (2 ^ (bitpos - 1))  
End Function
Private Function OpBit_Decimal(ByVal arg As Variant, _
  ByVal bitpos As Byte, _
  ByVal op As Byte) As Variant
 
  ' Setzen, Löschen, Abfragen eines Bit in einer
  ' Variant/Decimal-Variable
  ' Bitposition: 1 bis 96 (von links nach rechts)
 
  Dim l As Dec_Long, Index As Byte
 
  If bitpos > 96 Or bitpos < 1 Then
    OpBit_Decimal = arg: Exit Function
  End If
 
  ' Variant/Decimal umkopieren
  l = Decimal_Nach_Long(arg)
 
  ' Long für BitPosition ermitteln
  If bitpos < 33 Then
    Index = 2
  ElseIf bitpos < 65 Then
    Index = 3
    bitpos = bitpos - 32
  Else
    bitpos = bitpos - 64
    Index = 4
  End If
 
  If op > 2 Then
    ' Bit abfragen
    OpBit_Decimal = Ist_Bit_Gesetzt_Long(l.l(Index), bitpos)
  Else
    If op = 1 Then
      ' Bit setzen
      l.l(Index) = Setze_Bit_Long(l.l(Index), bitpos)
    Else
      ' Bit löschen
      l.l(Index) = Lösche_Bit_Long(l.l(Index), bitpos)
    End If
    ' Modifizierten Variant/Decimal zurückgeben
    OpBit_Decimal = Decimal_Von_Long(l)
  End If   
End Function
Private Function Decimal_Nach_Long(ByVal arg As Variant) As Dec_Long
  ' Variant/Decimal wird in Verwaltung und 3 Longs kopiert
  If VarType(arg) <> vbDecimal Then Exit Function
 
  Dim l As Dec_Long
  Call CopyMemory(VarPtr(l), VarPtr(arg), 16)
  Decimal_Nach_Long = l
End Function
Private Function Decimal_Von_Long(ByRef l As Dec_Long) As Variant
  ' Verwaltung und 3 Longs werden in eine Variant-Variable kopiert
 
  Dim arg As Variant
  arg = CDec(0)
  Call CopyMemory(VarPtr(arg), VarPtr(l), 16&)
  Decimal_Von_Long = arg
End Function
 
' ============================================================
' Ende Quellcode Modul: modBit
' ============================================================

Dieser Tipp wurde bereits 28.530 mal aufgerufen.

Voriger Tipp   |   Zufälliger Tipp   |   Nächster Tipp

Über diesen Tipp im Forum diskutieren
Haben Sie Fragen oder Anregungen zu diesem Tipp, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

Neue Diskussion eröffnen

nach obenzurück


Anzeige

Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Tipps & Tricks finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
(einschl. Beispielprojekt!)

Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
- nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
- Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
 
   

Druckansicht Druckansicht Copyright ©2000-2024 vb@rchiv Dieter Otter
Alle Rechte vorbehalten.
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel