1. Die Übertragung von Variablenwerten in ein 'BitArray' Zuerst wird über die GetBytes-Methode der BitConverter-Klasse ein Byte-Array mit der Bitfolge gefüllt, die in einer Variable enthalten ist. Diese Bits können dann in eine Instanz der BitArray-Klasse eingetragen werden - und zwar über deren Konstruktor. Zusammengefasst in einer Code-Zeile sieht das so aus: Dim Lng as Long = Long.MaxValue Dim ba As New BitArray(BitConverter.GetBytes(Lng)) Diese Zuweisung kann man mit allen integrierten numerischen Datentypen durchführen Ausnahme: der Datentyp Decimal. Der verfügt über eine integrierte Methode: Dim Dec as Decimal = Decimal.MaxValue ba = New BitArray(Decimal.GetBits(Dec)) Die Länge des auf diese Weise entstehenden Bitarrays richtet sich nach dem Datentyp der Variable, die an die GetBytes-Methode des Bitkonverters übergeben worden ist (null-basierter Index). Im Fall einer Long-Variable handelt es sich deshalb um eine Länge von 64 (Bit). Die in den Decimal-Datentyp integrierte Methode GetBits liefert (indirekt!) die 128 Bits, aus denen sich eine Decimal-Variable zusammensetzt. Allerdings ist zu beachten, dass Variable der Datentypen Decimal, Single und Double im Speicher 'codiert' vorliegen. Das bedeutet, durch Bit-Manipulationen erreicht man normalerweise nicht das gewünschte Ergebnis, weil die Bitfolge, als Numeric-Code ausgewertet (nach der IEEE bzw. der DECIMAL-Datentyp-Konvention) wird. Dazu noch eine Anmerkung: Es handelt sich bei den Bitfolgen, von denen hier die Rede ist, um die Datentyp-spezifische Repräsentation im Speicher, nicht um eine Konvertierung von Zahlenwerten vom Zehner- ins Binärsystem. Auch bei den vorzeichenbehafteten Ganzzahl-Datentypen Short, Integer oder Long ist die direkte Korrespondenz zwischen dem Wert der Variable im Zehnersystem und der Bedeutung der Bitfolge im Dualsystem nur gegeben, wenn das letzte Bit ( = die Kennung für eine negativ zu interpretierende Zahl) im Bit-Array nicht gesetzt ist. Anders bei den Unsigned-Varianten der Ganzzahltypen UShort, UInteger und ULong. Die Bits werden bei der Decodierung von links nach rechts ausgewertet: Den Inhalt von Stringvariablen muss man auf Bit-Ebene durch den Zugriff auf deren Chars-Auflistung sukzessive in einer Schleife auslesen. Die GetBytes-Methode der BitConverter-Klasse ist nämlich nur für den Datentyp ‚Character’ überladen (Für jedes übergebene Zeichen liefert sie in Form von 2 Bytes den zugeordneten UNICODE). 2. Die Übertragung von Bitmustern in integrierte Datentypen Dim byt as Byte = ba.Clone Dim byt as Byte = CType(ba.clone, Byte()) In VB fehlt offenbar eine elementare Konvertierungsfunktion (von Bits zu Bytes). Die Klasse 'BitArray' ist nicht im Namespace System.Array, sondern im Namespace System.Collection angesiedelt. Vermutlich liegt darin der Grund, weshalb es mit dem Clonen nicht klappt. Die CopyTo-Methode der BitArray-Klasse dient dazu, die Daten in ein Byte-Array zu übertragen. (Diese Methode ermöglicht auch Ziel-Arrays der Typen Boolean und Integer. Sie benutzt - laut Doku - intern die Array.Copy-Methode). Da die CopyTo-Methode mit einem Startindex arbeitet, kann sie die erforderliche Länge des Zielarray nicht selbst einrichten. Man muss deshalb zunächst eine Dimensionierung durchführen. Die erforderliche Mindestlänge des null-basierten Zielarray vom Typ Byte bei Startindex = 0 ist gegeben durch: Dim EBytes(ba.length \ 8 - 1) as Byte Der Kopiervorgang läuft dann über folgendes Kommando: Ba.CopyTo(EBytes, 0) Den Inhalt dieses Byte-Arrays kann der BitConverter weiterverarbeiten. Dessen Methode 'ToInt64' 'formt' aus 8 Byte ab der gegebenen Startposition einen vorzeichenbehafteten System.Int64 (= Long). Dim lng2 As Long = BitConverter.ToInt64(EBytes, 0) Der BitConverter enthält spezifische To...-Methoden für alle numerischen Datentypen - mit Ausnahme des Datentyps Decimal (dazu vgl. unten: SetBits2Decimal). Um die in ein Bytearray kopierten Bits statt in einen numerischen Datentyp wieder in eine Stringvariable zurück zu transportieren, ist eine Schleife erforderlich, die per Step 2 immer zwei Bytes aus UNICODE in ein Zeichen zurückverwandelt. 3. Details zur Klasse 'BitArray': Bit-Operationen Das IList-Interface ist implementiert (-> indizierter Zugriff auf einzelne Elemente), ebenso IEnumerable (-> For Each .. Next-Schleife) und ICloneable (Clone-Methode). Das BitArray steht nicht in einem Zusammenhang mit der Collection-Klasse (Microsoft.VisualBasic), und verfügt deshalb nicht über Methoden wie Add, Remove oder Clear. Ein BitArray darf man auch nicht verwechseln mit einem Array dessen Elemente aus dem Datentyp 'Boolean' bestehen. Boolean-Variable sind ein Byte lang. Im Zustand 'true' ist bei einem Boolean das erste Bit gesetzt, sonst nicht. Die anderen 7 Bits sind funktionslos ('false'). Anmerkung zur numerischen Repräsentation von 'True': Dim i, k As Integer i = CInt(true) k = Convert.ToInt32(true) Die beiden Integer enthalten keine identischen Werte. (i = -1; k = +1) Selbst bei einem ganz einfachen Bit hat das Framework mit VB so seine 'speziellen' Probleme. Mit den integrierten Ganzzahl-Datentypen können die OPERATOREN And, Or, Xor, Not auch direkt bitweise Operationen durchführen. Die Bitfolge muss dazu nicht in ein BitArray übertragen werden. Die VB-Dokumentation weist darauf hin, dass diese Operatoren in der Operator-Rangstufe einen sehr niedrigen Stellenwert haben und empfiehlt, sie ggf. geeignet in Klammern zu setzen. (Sie werden sonst erst nach den arithmetischen und den Vergleichs-Operatoren ausgewertet). Für die Manipulation eines BitArray stehen die METHODEN And, Or, Xor und Not zur Verfügung. Sie verknüpfen durch EINEN Aufruf ALLE Bits aus zwei korrespondierenden BitArrays auf jeweils spezifische Weise miteinander. Die beiden Arrays müssen allerdings die gleiche Länge aufweisen. Das (optionale!) Zielarray wird automatisch auf die entsprechende Länge eingerichtet. Zunächst werden zwei BitArrays (ba1, ba2) erstellt: Dim ba1 As New BitArray(BitConverter.GetBytes(lng1)) Dim ba2 As New BitArray(BitConverter.GetBytes(lng2)) Dim ba3 As BitArray = ba1.And(ba2) Folgendes geht übrigens nicht: ba3 = ba1 And ba2
AND (ebenso wie OR, XOR) ist in diesem Fall nämlich die Bezeichnung für eine (Bitkombinations-) Methode und ist nicht als Operator implementiert. Noch einmal zur Klarstellung: Zur Erinnerung: - die Arbeitsweise der Bit-Operatoren: Dim bb1 As New BitArray(4) Dim bb2 As New BitArray(4) bb1(0) = True : bb1(1) = True : bb1(2) = False : bb1(3) = False bb2(0) = True : bb2(1) = False : bb2(2) = True : bb2(3) = False bb1.And(bb2) ---> bb1 enthält: true, false, false, false (nur die Kombination true/true bleibt true) bb1 wird wieder auf den obigen Ausgangswert zurückgesetzt! bb1.Or(bb2) ---> bb1 enthält: true, true, true , false (nur die Kombination false/false bleibt false) bb1 wird wieder auf den obigen Ausgangswert zurückgesetzt! bb1.XOr(bb2) ---> bb1 enthält: false, true, true , false (nur sich unterscheidende Kombis werden true) ('exklusives oder') Nicht alle VB(6)-üblichen logischen Operatoren werden von den BitArray-Methoden direkt unterstützt. (Vgl. dazu ergänzend in der VB-Doku den Abschnitt 'Boolean Operator für Visual Basic 6 Users') Es fehlen die Imp- und die Eqv-Methode (Implikation und Äquivalenz). Die Imp-Verknüpfung bekommt man durch eine Kombination von 'Not' und 'Or': bb1.Not.Or(bb2) Auch die EQV-Verknüpfung ist durch eine geeignete Kombination zu erhalten (bb1 enthält danach die EQV-Bits): bb1.Xor(bb2).Not() Die Not-Methode invertiert alle Bits in einem Bitarray. Auch hier gilt. Falls ein Ziel-Array angegeben wird, erfolgt eine Übertragung der Ergebnis-Bits, aber: im Quell-Array sind die Bits dennoch ebenfalls umgesetzt worden. (Für den Aufruf der Not-Methode existiert eine undokumentierte Überladung, die einen Index übernimmt und einen Boolean zurückgibt. Trotz des Index-Parameters wird aber das gesamte Array invertiert. ???) Durch die SetAll-Methode können alle Bits im Bitarray auf den gleichen vorgegebenen Wert gesetzt werden. Diese Methode akzeptiert keine Angabe eines Ziel-Arrays. Man kann sie als Bit-Clear-Verfahren verwenden: SetAll(false) Einzelne Bit-Werte können - wie bei einem Array - direkt per nullbasiertem Index abgefragt oder geändert werden. Die explizite Verwendung der Set- und Get-Methoden ist nicht erforderlich. In VB gibt es zwei (nicht-zirkuläre) 'arithmetische' Bit-Shift-Operatoren, die für alle Ganzzahl-Datentypen zur Verfügung stehen ( <<, <<=, >>. =>>). Durch Übertragung der Bitmuster von Variablen in BitArrays lassen sich auf einfache Weise eigene (z.B. zirkuläre) Shift-Methoden programmieren. (Durch Verwendung des StartIndex-Parameters der CopyTo-Methode können die Bits 'nach links geshiftet' in ein Byte-Array kopiert und von dort weitergegeben werden.) Im Namespace Collections.Specialized befindet sich die Struktur 'BitVector32'. Dieser Struktur kann eine Integer-Variable zugeordnet werden. Sie erlaubt die Abfrage von Bits über frei definierbare Bitmasken und Abschnitte. Ihre Bedeutung liegt - laut VB-Dokumentation - in der relativ hohen Effizienz (Werttyp) mit der Bit-Operationen (z.B. im Sinne von 'Flag'-Bearbeitung) ausgeführt werden können. Hinweis: 4. Bit-Operationen bei der Bildbearbeitung (Falls Ihnen der folgende Code unverständlich ist, sollten Sie einen Blick in den Vb@rchiv Workshop Es wird eine Bilddatei benötigt (24-Bit-Bitmap oder JPG) Dim bmp As Bitmap = _ New Bitmap("Name_einer_Bilddatei_mit_24_Bit_Bitmap") ' Der folgende Code kopiert die Bilddaten in ein Byte-Array Dim bmp_rect As New Drawing.Rectangle(0, 0, bmp.Width, bmp.Height) Dim bmp_data As Drawing.Imaging.BitmapData = _ bmp.LockBits(bmp_rect, Drawing.Imaging.ImageLockMode.ReadWrite, _ bmp.PixelFormat) Dim bmp_ptr As IntPtr = bmp_data.Scan0 Dim bmp_bytes As Integer = bmp.Width * bmp.Height * 3 Dim bmp_array(0 To bmp_bytes - 1) As Byte Runtime.InteropServices.Marshal.Copy(bmp_ptr, bmp_array, 0, _ bmp_bytes) Jetzt bekommen wir das Bild als eine Folge von Bits Dim BmpBits As New BitArray(bmp_array) Ab hier kann jetzt bitweise manipuliert werden, z.B. die Kombination mit den Bits eines anderen Bildes, das entsprechend geladen worden ist. Durch den XOR-Operator würde das Ergebnisbild schwarz, weil es keine Unterschiede gibt BmpBits.Xor(BmpBits) Durch den EQV-Operator würde das Ergebnis-Bild weiss, weil alle Bits korrespondieren BmpBits.Xor(BmpBits).Not() Durch den NOT-Operator würde das Ergebnisbild invertiert BmpBits.Not() ' Hier werden die manipulierten Bits zurückkopiert BmpBits.CopyTo(bmp_array, 0) Runtime.InteropServices.Marshal.Copy( _ bmp_array, 0, bmp_ptr, bmp_bytes) bmp.UnlockBits(bmp_data) ' Und das Bild wird gespeichert bmp.Save("Dateiname_des_Zielbildes.bmp") 5. Beispiele zum 'BitArray' Public Function SetBits2Decimal(ByVal b As BitArray) As Decimal ' Übertragung von 128 Bits in eine Variable des ' Typs 'Decimal' ' Parameter prüfen If b.Length <> 128 Then Return CDec(0) ' Lokale Variable vereinbaren Dim i As Integer 'Loop Dim ByteArray(15) As Byte ' 16 Byte Dim IntArray(3) As Integer ' 4 Integer ' BitArray --> ByteArray b.CopyTo(ByteArray, 0) ' ByteArray --> IntegerArray For i = 0 To 3 IntArray(i) = BitConverter.ToInt32(ByteArray, i * 4) Next i ' IntegerArray --> Decimal Return New Decimal(IntArray) End Function Public Function SetBitArray2Integer( _ ByVal ba As BitArray) As Integer() ' Den Inhalt des BitArray in ein ' Integer-Array eintragen Dim intarr(ba.Length \ 32 - 1) As Integer ba.CopyTo(intarr, 0) Return intarr End Function Public Function SetUIntegerArray2BitArray( _ ByVal uint() As UInteger) As BitArray ' Den Inhalt des UInteger-Array in ein ' BitArray eintragen Dim i As Integer Dim byt1() As Byte ' Array für alle Bytes des UINT-Array Dim BytesTot(uint.Length * 4 - 1) As Byte For i = 0 To UBound(uint) ' Bytes eines Arrayelements besorgen ... byt1 = BitConverter.GetBytes(uint(i)) ' ... und in Gesamt-Bytearray kopieren Array.Copy(byt1, 0, BytesTot, i * 4, 4) Next i ' Alle Bytes als BitArray zurückgeben Return New BitArray(BytesTot) End Function Public Function SetBitArrayToUIntegerArray( _ ByVal ba As BitArray) As UInteger() ' Bits in einem BitArray in ein Array ' ' des Typs UInteger übertragen Dim Uint(0) As UInteger ' Parameter prüfen If ba.Length Mod 32 <> 0 Then Return Uint Dim i As Integer ' Korrespondierende Zahl der UInteger Dim ints As Integer = ba.Length \ 32 ReDim Uint(ints - 1) ' Byte-Array deklarieren Dim Bytestot(ints * 4 - 1) As Byte ' Bits --> Bytes ba.CopyTo(Bytestot, 0) ' Bytes --> UInteger For i = 0 To ints - 1 Uint(i) = _ BitConverter.ToUInt32(Bytestot, i * 4) Next i ' Rückgabe UInteger Return Uint End Function Public Function BitArray2DecimalValue( _ ByVal ba As BitArray) As Decimal ' Der Inhalt eines Bitarray bis max. 96 Bits wird als ' Wert im Zehnersystem dargestellt ' (Umwandlung von von links nach rechts) Dim i As Integer, dec As Decimal ' Eingabeparameter prüfen If ba.Length > 96 Then Return CDec(-1) For i = 0 To ba.Length - 1 If ba(i) Then dec += CDec(2 ^ i) Next i Return dec End Function Public Function BitArray2ULongValue( _ ByVal ba As BitArray) As ULong ' Der Inhalt eines Bitarray bis max. 64 Bits wird als ' Wert im Zehnersystem dargestellt (ULONG) ' (Umwandlung von von links nach rechts) Dim i As Integer, ulng As ULong ' Eingabeparameter prüfen If ba.Length > 64 Then Return CULng(0) For i = 0 To ba.Length - 1 If ba(i) Then ulng += CULng(2 ^ i) Next i Return ulng End Function Public Function SetLongArray2BitArray( _ ByVal lngarr() As Long) As BitArray ' Long-Array in Bitarray eintragen (Interop.Marshal) Dim bytes As Integer = lngarr.Length * 8 ' ByteArray deklarieren Dim bytarr(bytes - 1) As Byte ' Platz im Freispeicher reservieren/sperren Dim ptr As IntPtr = _ Runtime.InteropServices.Marshal.AllocCoTaskMem(bytes) ' Long-Array in den Freispeicher kopieren Runtime.InteropServices.Marshal.Copy(lngarr, 0, ptr, lngarr.Length) ' Byte-Array aus dem Freispeicher füllen Runtime.InteropServices.Marshal.Copy(ptr, bytarr, 0, bytarr.Length) ' Frei-Speicher wieder freigeben Runtime.InteropServices.Marshal.FreeCoTaskMem(ptr) ' ByteArray in BitArray umwandeln und zurückgeben Return New BitArray(bytarr) End Function Public Function SetBitArray2LongArray( _ ByVal ba As BitArray) As Long() ' Bitarray in Long-Array eintragen (Interop.Marshal) Dim lngarr(0) As Long ' Parameter prüfen If ba.Length Mod 64 <> 0 Then Return lngarr Dim bytes As Integer = ba.Length \ 8 ' Bytearray deklarieren Dim bytarr(bytes - 1) As Byte ' Bits in das Bytearray kopieren ba.CopyTo(bytarr, 0) ' LongArraqy deklarieren ReDim lngarr(bytes \ 8 - 1) ' Freispeicher reservieren / sperren Dim ptr As IntPtr = _ Runtime.InteropServices.Marshal.AllocCoTaskMem(bytes) ' Byte-Array in Freispeicher kopieren Runtime.InteropServices.Marshal.Copy(bytarr, 0, ptr, bytarr.Length) ' LongArray aus dem Freispeicher füllen Runtime.InteropServices.Marshal.Copy(ptr, lngarr, 0, lngarr.Length) ' Freispeichert freigeben Runtime.InteropServices.Marshal.FreeCoTaskMem(ptr) ' Long-Array zurückgeben Return lngarr End Function Dieser Workshop wurde bereits 11.068 mal aufgerufen.
Anzeige
![]() ![]() ![]() 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. |
Neu! sevCommand 4.0 ![]() Professionelle Schaltflächen im modernen Design! Mit nur wenigen Mausklicks statten auch Sie Ihre Anwendungen ab sofort mit grafischen Schaltflächen im modernen Look & Feel aus (WinXP, Office, Vista oder auch Windows 8), inkl. große Symbolbibliothek. Tipp des Monats ![]() Dieter Otter PopUp-Menü wird nicht angezeigt :-( In diesem Tipp verraten wir Ihnen, wie Sie Probleme mit PopUp-Menüs umgehen können, wenn diese unter bestimmten Umständen einfach nicht angezeigt werden. TOP Entwickler-Paket ![]() TOP-Preis!! Mit der Developer CD erhalten Sie insgesamt 24 Entwickler- komponenten und Windows-DLLs. Die Einzelkomponenten haben einen Gesamtwert von 1605.50 EUR... |
|||||||||||||
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. |