Rubrik: Variablen/Strings | VB-Versionen: VB2008 | 23.03.09 |
SetBits, GetBits: Zugriff auf die Bits numerischer Variablen Ein Modul mit SetBits- und Getbits-Überladungen für den Zugriff auf die Bits, die in numerischen Variablen enthalten sind | ||
Autor: Manfred Bohn | Bewertung: | Views: 11.330 |
ohne Homepage | System: Win2k, WinXP, Win7, Win8, Win10, Win11 | kein Beispielprojekt |
Bei den integrierten numerischen VB-Datentypen fehlt jeweils die 'SetBits' und 'GetBits'-Methode, durch die eine Bitfolge als Instanz der Klasse 'BitArray' abgerufen bzw. gesetzt werden kann.
Die 'BitConverter'-Klasse enthält alle benötigten Methoden, so dass die Erstellung eines Moduls, das die Erweiterungen (typspezifische Überladungen) enthält, eine einfache Fleißarbeit ist.
Bei den 'SetBits'-Überladungen kann durch den optionalen Parameter 'UseAny' festgelegt werden, ob die Länge des als Parameter übergebenen 'Bitarray' an die erforderliche Länge des Datentyps angepasst wird (Null-Bits anhängen bzw. Bits abschneiden) oder ob ggf. eine Ausnahme ausgelöst wird.
Boolsche Variable werden auf ein einzelnes Bit abgebildet!
Zur Demonstration sind im Modul 'modBitFunctions' zusätzlich die 'GetBit'/'SetBit'-Überladungen für Integer und Decimal enthalten, durch die ein direkter, indizierter Bit-Zugriff möglich ist.
Die 'Bits2String'- und 'String2Bits'-Erweiterungen dienen zur Veranschaulichung des Bit-Inhaltes numerischer Variablen.
Option Strict On Option Explicit On Option Infer Off Imports System ' BitConverter-Klasse Imports System.Collections ' BitArray-Klasse Imports System.Runtime.CompilerServices ' Extension-Attribut Namespace Bit_Functions ''' <summary>Bit-Bearbeitung durch BitArrays</summary> Public Module mod_Set_Get_Bits
' ================================================================ ' GetBits-Überladungen ' ================================================================ ''' <summary>Boolean-Bit in Bitarray eintragen</summary> ''' <param name="arg">Boolean-Variable</param> ''' <returns>Bitarray (1 Bit)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Boolean) As BitArray Dim ba As New BitArray(1) ' Length!! ba(0) = arg : Return ba End Function ''' <summary>Byte-Bits in Bitarray eintragen</summary> ''' <param name="arg">Byte-Variable</param> ''' <returns>Bitarray (8 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Byte) As BitArray Dim byt(0) As Byte ' Ubound!! byt(0) = arg : Return New BitArray(byt) End Function ' ab hier wird der BitConverter eingesetzt: ' ----------------------------------------- ''' <summary>Char-Bits in Bitarray eintragen</summary> ''' <param name="arg">Char-Variable</param> ''' <returns>Bitarray (8 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Char) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Short-Bits in Bitarray eintragen</summary> ''' <param name="arg">Short-Variable</param> ''' <returns>Bitarray (16 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Short) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>UShort-Bits in Bitarray eintragen</summary> ''' <param name="arg">UShort-Variable</param> ''' <returns>Bitarray (16 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As UShort) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Integer-Bits in Bitarray eintragen</summary> ''' <param name="arg">Integer-Variable</param> ''' <returns>Bitarray (32 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Integer) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>UInteger-Bits in Bitarray eintragen</summary> ''' <param name="arg">UInteger-Variable</param> ''' <returns>Bitarray (32 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As UInteger) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Long-Bits in Bitarray eintragen</summary> ''' <param name="arg">Long-Variable</param> ''' <returns>Bitarray (64 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Long) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>ULong-Bits in Bitarray eintragen</summary> ''' <param name="arg">ULong-Variable</param> ''' <returns>Bitarray (64 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As ULong) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Single-Bitmuster in Bitarray eintragen</summary> ''' <param name="arg">Single-Variable</param> ''' <returns>Bitarray (32 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Single) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Double-Bitmuster in Bitarray eintragen</summary> ''' <param name="arg">Double-Variable</param> ''' <returns>Bitarray (64 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Double) As BitArray Return New BitArray(BitConverter.GetBytes(arg)) End Function ''' <summary>Decimal-Bits in Bitarray eintragen</summary> ''' <param name="arg">Decimal-Variable</param> ''' <returns>Bitarray (128 Bits)</returns> <Extension()> _ Public Function GetBits(ByVal arg As Decimal) As BitArray Return New BitArray(Decimal.GetBits(arg)) End Function
' ================================================================= ' SetBits-Überladungen ' ================================================================= ''' <summary>Bitarray in Boolean eintragen (1 Bit!!)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Boolean, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) GetBytes(ba, 1, UseAny) vl = ba(0) End Sub ''' <summary>Bitarray in Byte-Variable eintragen (8 Bit)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Byte, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = GetBytes(ba, 8, UseAny)(0) End Sub ' ab hier wird der BitConverter eingesetzt: ' ----------------------------------------- ''' <summary>Bitarray in Short-Variable eintragen (16 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Short, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToInt16(GetBytes(ba, 16, UseAny), 0) End Sub ''' <summary>Bitarray in UShort-Variable eintragen</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As UShort, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToUInt16(GetBytes(ba, 16, UseAny), 0) End Sub ''' <summary>Bitarray in Integer-Variable eintragen (32 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Integer, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToInt32(GetBytes(ba, 32, UseAny), 0) End Sub ''' <summary>Bitarray in UInteger-Variable eintragen (32 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As UInteger, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToUInt32(GetBytes(ba, 32, UseAny), 0) End Sub ''' <summary>Bitarray in Long-Variable eintragen (64 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Long, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToInt64(GetBytes(ba, 64, UseAny), 0) End Sub ''' <summary>Bitarray in ULong-Variable eintragen (64 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As ULong, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToUInt64(GetBytes(ba, 64, UseAny), 0) End Sub ''' <summary>Bitarray in Single-Variable eintragen (32 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Single, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToSingle(GetBytes(ba, 32, UseAny), 0) End Sub ''' <summary>Bitarray in Double-Variable eintragen (64 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Double, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) vl = BitConverter.ToDouble(GetBytes(ba, 64, UseAny), 0) End Sub ''' <summary>Bitarray in Decimal-Variable eintragen (128 Bits)</summary> ''' <param name="vl">Ziel-Variable (wird überschrieben)</param> ''' <param name="ba">einzutragendes Bitarray</param> ''' <param name="UseAny">Arraylänge ggf. anpassen?</param> <Extension()> _ Public Sub SetBits(ByRef vl As Decimal, _ ByVal ba As BitArray, _ Optional ByVal UseAny As Boolean = False) ' BitArray --> ByteArray Dim byt() As Byte = GetBytes(ba, 128, UseAny) ' ByteArray --> IntegerArray Dim intarray(3) As Integer For i As Integer = 0 To 3 intarray(i) = BitConverter.ToInt32(byt, i * 4) Next i ' IntegerArray --> Decimal vl = New Decimal(intarray) End Sub Private Function GetBytes(ByRef ba As BitArray, _ ByVal Length As Integer, _ ByVal UseAny As Boolean) As Byte() ' Hilfsfunktion SetBits-Überladungen ' BitArray kontrolliert in ein Byte-Array übertragen Dim ok As Boolean = True If ba Is Nothing Then ok = False If Length < 1 Or Length > 128 Then ok = False If ba.Length < 1 Or ba.Length > 128 Then ok = False If Not ok Then Throw New ArgumentException("Ungeeigneter oder fehlender Parameter") End If If ba.Length <> Length Then If Not UseAny Then Throw New ArgumentException("Exakt " + CStr(Length) + " Bits werden benötigt") End If End If If Length Mod 8 <> 0 Then If Not UseAny Then Throw New ArgumentException("Bit-Länge muss ein Vielfaches von 8 sein") End If Length = ((Length \ 8) + 1) * 8 End If ' ggf. Bits abschneiden oder 0-Bits hinzufügen ba.Length = Length ' Bits --> Bytes Dim Bytes(ba.Length \ 8 - 1) As Byte ba.CopyTo(Bytes, 0) ' Rückgabe Return Bytes End Function
' ================================================================== ' SetBit / GetBit: ' Direkter, indizierter Zugriff auf ein Variablen-Bit im ' rufenden Programm (Beispiele für Integer-, Decimal-Erweiterung) ' ================================================================== ''' <summary>Eintragen eines Bit in eine Integer-Variable</summary> ''' <param name="arg">Integer-Variable (Ziel)</param> ''' <param name="Index">Bit-Index (0-31)</param> ''' <param name="BitValue">einzutragender Bit-Wert</param> <Extension()> _ Public Sub SetBit(ByRef arg As Integer, ByVal Index As Integer, _ ByVal BitValue As Boolean) If Index < 0 Or Index > 31 Then Throw New ArgumentOutOfRangeException _ ("Der Bit-Index liegt ausserhalb der Breite des Datentyps") End If Dim ba As BitArray = arg.GetBits ba(Index) = BitValue : arg.SetBits(ba) End Sub ''' <summary>Abfragen eines Bits in einer Integer-Variable</summary> ''' <param name="arg">Integer-Variable (Quelle)</param> ''' <param name="Index">Bit-Index (0-31)</param> ''' <returns>aktueller Wert des Bits</returns> <Extension()> _ Public Function GetBit(ByVal arg As Integer, ByVal Index As Integer) As Boolean If Index < 0 Or Index > 31 Then Throw New ArgumentOutOfRangeException _ ("Der Bit-Index liegt ausserhalb der Breite des Datentyps") End If Dim ba As BitArray = arg.GetBits Return ba(Index) End Function ''' <summary>Eintragen eines Bit in eine Decimal-Variable</summary> ''' <param name="arg">Decimal-Variable (Ziel)</param> ''' <param name="Index">Bit-Index (0-127)</param> ''' <param name="BitValue">einzutragender Bit-Wert</param> <Extension()> _ Public Sub SetBit(ByRef arg As Decimal, ByVal Index As Integer, _ ByVal BitValue As Boolean) If Index < 0 Or Index > 127 Then Throw New ArgumentOutOfRangeException _ ("Der Bit-Index liegt ausserhalb der Breite des Datentyps") End If Dim ba As BitArray = arg.GetBits ba(Index) = BitValue : arg.SetBits(ba) End Sub ''' <summary>Abfragen eines Bits in einer Decimal-Variable</summary> ''' <param name="arg">Decimal-Variable (Quelle)</param> ''' <param name="Index">Bit-Index (0-127)</param> ''' <returns>aktueller Wert des Bits</returns> <Extension()> _ Public Function GetBit(ByVal arg As Decimal, ByVal Index As Integer) As Boolean If Index < 0 Or Index > 127 Then Throw New ArgumentOutOfRangeException _ ("Der Bit-Index liegt ausserhalb der Breite des Datentyps") End If Dim ba As BitArray = arg.GetBits Return ba(Index) End Function
' ========================================================= ' Umwandlung: BitArray <--> 0/1-String ' ========================================================= ''' <summary>Inhalt eines Bitarray in 0/1-String eintragen</summary> ''' <param name="ba">Bitarray (Quelle)</param> ''' <param name="ByteSeparator"> ''' Gruppen von 8 Bits durch Space trennen?</param> ''' <returns>Bit-String</returns> <Extension()> _ Public Function Bits2String(ByVal ba As BitArray, _ Optional ByVal ByteSeparator As Boolean = True) As String If ba Is Nothing Then Return Nothing If ba.Length < 1 Then Return "" Dim str As String = "" For i As Integer = 0 To ba.Length - 1 If ba(i) Then str &= "1" Else str &= "0" If ByteSeparator Then If (i + 1) Mod 8 = 0 Then str &= " " End If Next i Return str.Trim End Function ''' <summary>Ein Bit-String (Charakter '1'=true, sonst false) wird ''' in ein Bitarray eingetragen-Spaces werden zuvor entfernt</summary> ''' <param name="bits">Bit-String (Quelle)</param> ''' <returns>Bitarray</returns> <Extension()> _ Public Function String2Bits(ByVal bits As String) As BitArray If String.IsNullOrEmpty(bits) Then Return Nothing Dim Str As String = bits.Replace(" ", "").Trim If Str.Length = 0 Then Return Nothing Dim ba As New BitArray(Str.Length) For i As Integer = 0 To Str.Length - 1 If Str = "1" Then ba(i) = True Next i Return ba End Function
End Module End Namespace
Einige Beispiele:
Public Sub Ex_BitFunctions() Console.WriteLine() Console.WriteLine("Beispiele für Bitmuster:") Console.WriteLine() ' Das 33. Bit in einer Decimal-Variable setzen und das ' Bitmuster in der Standardausgabe als String anzeigen Dim dec As Decimal = CDec(2 ^ 32) Console.WriteLine("Decimal-Bits: " + CStr(dec)) Console.WriteLine(dec.GetBits.Bits2String()) ' Die Bitfolge in eine zweite Decimal-Variable übertragen Dim dec2 As Decimal dec2.SetBits(dec.GetBits) If dec2 <> CDec(2 ^ 32) Then Stop ' sollte nicht sein ' Das sechste Bit wird gesetzt (und wg. des ' negativen Vorzeichens auch alle folgenden Bits) Dim shrt As Short = -1S * CShort(2 ^ 5) Console.WriteLine("Short-Bits: " + CStr(shrt)) Console.WriteLine(shrt.GetBits.Bits2String()) ' Der UseAny-Parameter erlaubt das Eintragen der ' 16-Short-Bits in die Long-Variable ' Das Bitmuster des negativen Short-Wertes wird ' im Datentyp Long anders interpretiert Dim lng As Long lng.SetBits(shrt.GetBits, True) Console.WriteLine("Long-Bits: " + CStr(lng)) Console.WriteLine(lng.GetBits.Bits2String()) ' Das fünfte UND neunte Bit in 'Integ' wird gesetzt Dim integ As Integer = CInt(2 ^ 4) Or CInt(2 ^ 8) Console.WriteLine("Integer-Bits: " + CStr(integ)) Console.WriteLine(integ.GetBits.Bits2String()) ' Das neunte Bit wird gelöscht (null-basierter Index) integ.SetBit(8, False) Console.WriteLine("Integer-Bits: " + CStr(integ)) Console.WriteLine(integ.GetBits.Bits2String()) ' Kleinster von 0 unterscheidbarer Decimalwert ' im 15. Byte steht die Potenz des ' Decimal-Skalierungs-Divisors (max. 28) dec = CDec(1.0E-28) Console.WriteLine("Decimal-Bits: " + CStr(dec)) Console.WriteLine(dec.GetBits.Bits2String()) ' IEEE-Bitmuster besteht aus Mantisse und Exponent! Dim sng As Single = 9999999.0! Console.WriteLine("Single-Bits: " + CStr(sng)) Console.WriteLine(sng.GetBits.Bits2String()) End Sub