n Bits eines Bytes lesen und Startposition von links angeben

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    n Bits eines Bytes lesen und Startposition von links angeben

    Hallo zusammen,

    ich möchte für ein Projekt eine VB.NET-Funktion (.NET Framework 4.8.1) schreiben, die mir n Bits eines Bytes zurückgibt. Die Startposition soll von der linken Seite aus angegeben werden. Das ist wichtig, da die Funktion auch von anderen Funktionen aufgerufen wird, und ich nun innerhalb dieses einen Bytes von links aus ein paar Bytes (nicht unbedingt bis zum Ende) lesen muss.

    Beispiel 1:
    0001 1111 (31)
    Funktionsaufruf ReadBitsL(31, 3, 5) gibt 31 zurück, weil Position = 3 und numBits = 5 und die übergebene Zahl auch 31 ist.

    Beispiel 2:
    1110 0000 (224)
    Funktionsaufruf ReadBitsL(224, 0, 3) gibt 224 zurück, weil Position = 0 und numBits=3 und weil die übergebene Zahl auch 224 ist.

    Es gibt zwar viele Beispiele bei Google, aber alle geben was unterschiedliches zurück, sowohl von den Ergebnissen als auch vom Datentyp. Ich habe wenig Erfahrung mit Bitschieben und schätze eure Hilfe!

    Dies ist mein bisheriger Versuch:

    VB.NET-Quellcode

    1. Private Function ReadBitsL(value As Byte, startPosition As Integer, numBits As Integer) As Byte
    2. Dim mask As Integer = (1 << numBits) - 1
    3. Dim rightShift As Integer = 7 - startPosition
    4. Dim shiftedValue As Byte = CByte((value >> rightShift) And mask)
    5. Return shiftedValue
    6. End Function


    Viele Grüße
    Bartosz

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Also für Bits kannste ein BitArray nehmen, aber auch genauso gut ein Bool-Array, oder List etc....

    C#-Quellcode

    1. private BitArray GetBits(byte _byte, int startPos, int count)
    2. {
    3. BitArray bits = new BitArray(count);
    4. for(int i = 0; i < count; i++)
    5. {
    6. bits[i] = (_byte & (1 << (startPos + i))) != 0;
    7. }
    8. return bits;
    9. }


    Im Grunde eine einfache Sache, du musst nur schauen ob Bits von einem Integer-Datentyp(also alle Ganzzahligen Typen, kein Gleitkomma) gesetzt sind.

    Mit 1 << Pos eine "Maske" erstellen. Wenn dann Maske AND Wert von einer Ganzahl ungleich null ist, ist das Bit an diese Position gesetzt. In der Maske ist so immer nur 1 Bit gesetzt, und nur wenn das selbe Bit im Byte gesetzt ist, kommt beim AND irgendeine Zahl ungleich 0 raus, hängt natürlich von der Position des gesetzten Bits ab.





    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DTF“ ()

    Wenn ich richtig verstehe sind deine Bytes immer echte Bytes?
    Du solltest auch mal ein Beispiel machen, wo ReadBitsL(N, a, b) <> N

    Also für ReadBitsL(31,0,1) Denke ich mal soll 0 rauskommen und ReadBitsL(31,3,2) = 3?
    Dann einfach erst die vorderen Zahlen rausschieben, dann die hinteren.

    VB.NET-Quellcode

    1. Private Function ReadBitsL(value As Byte, startPosition As Integer, numBits As Integer) As Byte
    2. Return value << startPosition >> (8 - numBits)
    3. End Function

    Bartosz schrieb:

    Der Wert 128 war zu groß. Das funktioniert so nicht.


    Ich tippe auf einen Fehler, du wirst das sicher zu VB übersetzt haben, da könnte sich was eingeshclichen haben. Oder hast du für Position eine 8 reingegeben? Die position wäre auch 0 Basiert. Also pos 0 = 1. Bit. Wäre gut deinen Code zu sehen.

    @Haudruferzappeltnoch So wie du das gemacht hast, hast du mehr Bits als gewollt, würde ich vermuten. So müssten die ja immer noch irgendwie "extrahiert" werden.

    PS @Bartosz
    Wie meinst du das mit dem Summieren? Anzahl gesetzter Bits? Oder aus den Bits wieder ein Byte machen, um eine Zahl darzustellen?
    Bilder
    • Unbenannt.jpg

      108,88 kB, 868×485, 12 mal angesehen
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „DTF“ ()

    @DTF Nein, natürlich habe ich 0 als Startposition eingegeben. Aber ich möchte eh kein BitArray als Rückgabetyp haben.
    Aus den Bits wieder ein Byte machen, um eine Zahl darzustellen :)

    @Haudruferzappeltnoch Was sind denn "echte Bytes"?
    Korrekt, für ReadBitsL(31,0,1) muss 0 rauskommen.
    Dein Beispiel funktioniert mit der 31, aber nicht mit der 224.
    Naja echte Bytes nur 8 Bits halt Byte Datentyp, also mit Integer und Short musst du die Bitlänge anpassen. Ich wollte nur sicherstellen, dass man generell von 8 Bits ausgeht.

    Bei mir funktionierts auch mit der 224, zeig mir dein Gegenbeispiel

    Achso ja seh schon du willst (224,0,3) = 224, bei mir kommt da 7 raus.
    Weil 1110 0000 Pos 0 bis 2 = 111 = 7

    Aber dann brauch ich wie gesagt andere Beispielfälle. Dann scheint ja ReadBitsL(31,3,2) = 3 auch schon eine verkehrte Annahme zu sein.
    Was ist ReadBitsL(31,3,2) bei dir? 24?
    Dann musst du nur wieder noch zurückschieben.

    VB.NET-Quellcode

    1. Private Function ReadBitsL(value As Byte, startPosition As Integer, numBits As Integer) As Byte
    2. Return value << startPosition >> (8 - numBits) << (8 - numBits - start)
    3. End Function

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    @Haudruferzappeltnoch
    Ich erhalte nicht 224.

    VB.NET-Quellcode

    1. ' 0000 0000 1110 0000 0000 0000
    2. ' 0000 0000 1110 0000 0000 0000
    3. '--------------------------------
    4. ' 0000 0000 1110 0000 0000 0000
    5. Dim readBitsResult2 As Byte = ReadBitsL(224, 0, 3)
    6. Debug.WriteLine("ReadBitsL 224 " & readBitsResult2.ToString())


    VB.NET-Quellcode

    1. Private Function ReadBitsL(value As Byte, startPosition As Integer, numBits As Integer) As Byte
    2. Return value << startPosition >> (8 - numBits)
    3. End Function


    Ausgabe

    Quellcode

    1. ReadBitsL 31 31
    2. ReadBitsL 224 7
    3. ReadBitsL 96 3


    @Haudruferzappeltnoch Meine Beispiele

    VB.NET-Quellcode

    1. ' 0000 0000 0001 1111 0000 0000
    2. ' 0000 0000 0001 1111 0000 0000
    3. '--------------------------------
    4. ' 0000 0000 0001 1111 0000 0000
    5. Dim readBitsResult1 As Byte = ReadBitsL(31, 3, 5)
    6. Debug.WriteLine("ReadBitsL 31 " & readBitsResult1.ToString())
    7. ' 0000 0000 1110 0000 0000 0000
    8. ' 0000 0000 1110 0000 0000 0000
    9. '--------------------------------
    10. ' 0000 0000 1110 0000 0000 0000
    11. Dim readBitsResult2 As Byte = ReadBitsL(224, 0, 3)
    12. Debug.WriteLine("ReadBitsL 224 " & readBitsResult2.ToString())
    13. ' 0000 0000 0110 0000 0000 0000
    14. ' 0000 0000 0110 0000 0000 0000
    15. '--------------------------------
    16. ' 0000 0000 0110 0000 0000 0000
    17. Dim readBitsResult3 As Byte = ReadBitsL(96, 1, 2)
    18. Debug.WriteLine("ReadBitsL 96 " & readBitsResult3.ToString())


    Was ist ReadBitsL(31,3,2) bei dir? 24?
    Ja, 24, weil 0001 1000

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    null Das scheint zu klappen. Ich teste noch ein wenig, und dann melde ich mich final.

    VB.NET-Quellcode

    1. Private Function ReadBitsL(value As Byte, startPosition As Integer, numBits As Integer) As Byte
    2. Return value << startPosition >> (8 - numBits) << (8 - numBits - start)
    3. End Function


    Danke dir

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Das hier sollte auch gehen: Finde ich sogar leichter zu lesen, wenn man weis das aus:
    1 << 5 = 0b00100000 wird, das denn -1 = 0b00011111, dann erkennt man sofort eine Maske mit der Anzahl an gesetzen Bits(count=Anzahl gesetzte Bits direkt am beginn). Braucht die Maske nur noch ein Shift, Wert AND Maske und dann zurückshiften.

    C#-Quellcode

    1. private byte MyByteFilter(byte _byte, int startPos, int count)
    2. {
    3. int mask = ((1 << count) - 1) << startPos;
    4. return (byte)(mask & _byte >> startPos);
    5. }

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Hallo @DTF,
    vielen Dank für deine Bemühungen. Leider funktioniert der vorgeschlagene Ansatz in meinem Fall nicht wie erwartet. Bei meinem Beispiel, wo value = 101, startPosition = 5 und numBits = 3 sind, sollte das Ergebnis 5 sein. Deine Funktion liefert jedoch 0 zurück.

    0110 0101 = 101
    _________
    0000 0101 = 5
    @Bartosz

    Ich denke du verdrehst da etwas. Das letzte Bit steht an erster Stelle. Um bei der 101 DEC an eine 5 zu kommen, wäre StartPos 0 und Anzahl 3.

    C#-Quellcode

    1. for(int i = 0; i < 8; i++)
    2. {
    3. Debug.WriteLine($"Wert: {i} = 0b{Convert.ToString(i, 2).PadLeft(8, '0')}");
    4. for (int j = 0; j < 8; j++)
    5. {
    6. Debug.WriteLine($"->Bit: {j} {(i & (1 << j)) != 0}");
    7. }
    8. Debug.WriteLine("");
    9. Debug.WriteLine("");
    10. }


    PS:
    @Bartosz
    Ich habe das eben von Hand gerechnet, Ergebnis sollte 3 sein mit deinen Werten

    (1 << 3) - 1 = 0b00000111
    0b00000111 << 5 = 0b11100000
    0b01100101 AND 0b11100000 = 0b01100000
    0b01100000 >> 5 = 0b00000011

    Ich hatte aber trotzdem einen Fehler im Code, ich hab nicht ausreichend getestet.
    Hab da eben noch ein Satz Klammern eingefügt.

    C#-Quellcode

    1. private byte MyByteFilter(byte _byte, int startPos, int count)
    2. {
    3. int mask = ((1 << count) - 1) << startPos;
    4. return (byte)((mask & _byte) >> startPos);
    5. }


    2 Begriffe noch für dich + Erklärung: Least Significant Bit(LSB) und Most Significant Bit (MSB).
    (Gehen wir hier von 8 Bits aus)
    Das LSB stellt den niedriegsten Wert dar, das steht ganz rechts, wenn nur das gesetzt ist, ist der Decimalwert 1
    Das MSB stellt den höchsten Wert dar, das steht ganz links, wenn nur das gesetzt ist, ist der Decimalwert 128
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „DTF“ ()

    @Haudruferzappeltnoch
    Ja, aus der Perspektive würde das passen. Aber das ist mathematisch inkorrekt.

    Sollte @Bartosz das umgedreht haben wollen, dann sollte er das auch "umdrehen". So kommt nun 5 raus.

    C#-Quellcode

    1. private void Form1_Load(object sender, EventArgs e)
    2. {
    3. byte x = ReverseBits(101);
    4. x = MyByteFilter(x, 5, 3);
    5. }
    6. private byte ReverseBits(byte _byte)
    7. {
    8. return (byte)((_byte * 0x0202020202 & 0x010884422010) % 1023);
    9. }
    10. private byte MyByteFilter(byte _byte, int startPos, int count)
    11. {
    12. int mask = ((1 << count) - 1) << startPos;
    13. return (byte)((mask & _byte) >> startPos);
    14. }


    PS.
    Jetzt habe ich erst "von links" im Titel bemerkt. Das war die Info mir fehlte, und deshalb war ich auf dem Holzweg.

    Bartosz schrieb:

    Ich habe wenig Erfahrung mit Bitschieben und schätze eure Hilfe!


    Diese Seite solltest du dir dann mal speichern:
    graphics.stanford.edu/~seander/bithacks.html

    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „DTF“ ()