Wie extrahiere ich bestimmte ‘n’ Bits einer 32-Bit-Ganzzahl ohne Vorzeichen in C?

Lesezeit: 2 Minuten

Benutzeravatar von hektor
hektor

Kann mir jemand sagen, wie man ‘n’ bestimmte Bits aus einer 32-Bit-Ganzzahl ohne Vorzeichen in C extrahiert.

Angenommen, ich möchte die ersten 17 Bits des 32-Bit-Werts; was soll ich tun?
Ich nehme an, ich soll den Modulo-Operator verwenden, und ich habe es versucht und konnte die letzten 8 Bits und die letzten 16 Bits als erhalten

unsigned last8bitsvalue=(32 bit integer) % 16
unsigned last16bitsvalue=(32 bit integer) % 32

Ist das richtig? Gibt es einen besseren und effizienteren Weg, dies zu tun?

  • Beachten Sie, dass Ihr geschriebener Code tatsächlich die letzten 4 bzw. 5 Bits extrahiert (nicht 8 und 16, wie Sie geschrieben haben).

    – Aaron Dufour

    4. November 2011 um 16:20 Uhr

  • @AaronDufour Kannst du bitte deinen Kommentar erklären. Mich interessiert, warum das 4 und 5 Bit sind

    – Cholthi Paul Ttiopic

    12. Juni 2018 um 7:11 Uhr


  • @CholthiPaulTtiopic Sie können die letzten n Bits einer Zahl x mit erhalten x % (2 ^ n) (x % 16 -> x % 2^4 -> 4 Bit, und ähnlich x % 32 -> 5 Bit). Wenn Sie tun x % n dann werden Sie feststellen, dass Ihre Ausgabe nur von 0 bis n-1 reicht, während n Bits Zahlen von 0 bis 2^n-1 enthalten können.

    – Aaron Dufour

    13. Juni 2018 um 0:11 Uhr

  • @AaronDufour fantastische Erklärung!

    – Cholthi Paul Ttiopic

    13. Juni 2018 um 5:02 Uhr

Anstatt es als „extrahieren“ zu betrachten, betrachte ich es lieber als „isolieren“. Sobald die gewünschten Bits isoliert sind, können Sie damit machen, was Sie wollen.

Um einen beliebigen Satz von Bits zu isolieren, wenden Sie eine UND-Maske an.

Wenn Sie die letzten X Bits eines Werts benötigen, gibt es einen einfachen Trick, der verwendet werden kann.

unsigned  mask;
mask = (1 << X) - 1;
lastXbits = value & mask;

Wenn Sie eine Reihe von X Bits in der Mitte von ‘value’ isolieren möchten, beginnend bei ‘startBit’ …

unsigned  mask;
mask = ((1 << X) - 1) << startBit;
isolatedXbits = value & mask;

Hoffe das hilft.

  • Ihre Betonung darauf, zuerst Maskenbyte zu erstellen, ist wirklich hilfreich, um solche Probleme zu lösen

    – Pranav Nandan

    8. März 2016 um 14:12 Uhr

  • Benötigen Sie weitere Erläuterungen zum Maskieren des Teils. nicht viel bekommen

    – Benutzer765443

    21. Februar 2017 um 15:54 Uhr

  • @ user765443: Angenommen, Sie möchten die letzten 3 Bits aus 0101 extrahieren, 1 << 3 = 1000,1000-1 = 0111,0101 & 0111 = 101 (letzte 3 Bits extrahiert). (1<

    – AlphaGoku

    2. April 2018 um 3:20 Uhr

  • Dieser Ansatz funktioniert nicht, wenn X = 32 für int (oder 64 für long)

    – knst

    13. Oktober 2020 um 9:03 Uhr

  • @knst – Sie haben Recht; Unter den von Ihnen genannten Bedingungen stoßen wir beim Bit-Shifting auf undefiniertes Verhalten. Je nach Prozessor kann es also funktionieren (oder nicht); mit anderen Worten, es ist für diese Fälle nicht tragbar. Es kann auch die Beobachtung gemacht werden, dass Sie, wenn Sie versuchen, alle Bits zu extrahieren oder zu isolieren, einfach wie gewohnt auf die Variable zugreifen und sich nicht die Mühe machen, unnötige Masken anzuwenden.

    – Funkelnd

    13. Oktober 2020 um 18:47 Uhr

Benutzeravatar von pnezis
pnezis

Wenn Sie n Bits spezifisch möchten, können Sie zuerst eine Bitmaske erstellen und dann AND es mit Ihrer Nummer, um die gewünschten Bits zu nehmen.

Einfache Funktion zum Erstellen einer Maske von Bit a bis Bit b.

unsigned createMask(unsigned a, unsigned b)
{
   unsigned r = 0;
   for (unsigned i=a; i<=b; i++)
       r |= 1 << i;

   return r;
}

Sie sollten prüfen, ob a<=b.

Wenn Sie die Bits 12 bis 16 wollen, rufen Sie die Funktion auf und dann einfach & (logisches UND) r mit deiner nummer N

r = createMask(12,16);
unsigned result = r & N;

Wenn Sie möchten, können Sie das Ergebnis verschieben. Hoffe das hilft

  • Sie müssen keine Zeit damit verbringen, nach einer kleinen Maske zu suchen. nur((1 << n) - 1) << b

    – phuklv

    29. August 2013 um 10:07 Uhr

  • @pnezis Ich denke, Ihre Funktion schlägt mit einem Grenzfall fehl. Wenn ich die ersten beiden Bits haben möchte, createMask gibt mir das 2. und 3. Bit, weil es tun würde 1 << 1gefolgt von 1 << 2. Die zurückgegebene Bitmaske ist 110 – was das erste Bit auf Null setzt.

    – Jack

    14. März 2016 um 9:32 Uhr


  • @Jack, wenn du die ersten beiden Bits willst, musst du anrufen createMask mit 0 und 1 als Argumente, um die zu erhalten 0x03 Maske.

    – Pneumonien

    16. März 2016 um 13:09 Uhr

  • Das geht schneller und hat bei mir auch funktioniert uint64_t‘s: ((1ull << (b - a)) - 1ull) << a

    – Petr Manek

    26. Dezember 2016 um 13:54 Uhr

Modul funktioniert, um (nur) untere Bits zu bekommen, obwohl ich denke value & 0x1ffff drückt “nimm die unteren 17 Bits” direkter aus als value % 131072und ist daher leichter zu verstehen, als dies zu tun.

Die obersten 17 Bits eines 32-Bit-Werts ohne Vorzeichen wären value & 0xffff8000 (wenn Sie möchten, dass sie immer noch an ihren Positionen oben sind), oder value >> 15 wenn Sie die oberen 17 Bits des Werts in den unteren 17 Bits des Ergebnisses haben möchten.

  • Für den zweiten Teil Ihrer Antwort sollten Sie vielleicht haben value >> 15 & 0x1ffff. Die Rechtsverschiebung für ganze Zahlen ist implementierungsdefiniert; Sowohl GCC als auch MSVC haben es arithmetisch, nicht logisch.

    – Joseph Quinsey

    4. November 2011 um 18:39 Uhr

  • @Joseph: Die Frage besagt, dass es sich um eine 32-Bit-Ganzzahl ohne Vorzeichen handelt, sodass das Ergebnis der Rechtsverschiebung vom Standard definiert wird. Wenn es signiert wäre, ist die Auswirkung der Rechtsverschiebung auf einen negativen Wert (wie Sie sagen) vollständig implementierungsdefiniert. Es muss weder arithmetisch noch logisch sein, das Ergebnis kann alles sein. In der Praxis wählt natürlich jeder eine arithmetische Verschiebung für vorzeichenbehaftete Werte, aber wenn Sie Bedenken haben, nach dem Standard zu schreiben, ist es besser, dies ganz zu vermeiden (wie der Fragesteller es getan hat).

    – Steve Jessop

    4. November 2011 um 23:46 Uhr


Benutzeravatar von jfs
jfs

Es gibt eine einzige BEXTR (Bitfeldextrakt (mit Register)) x86-Anweisung auf Intel- und AMD-CPUs und UBFX auf ARM. Es gibt intrinsische Funktionen wie z _bextr_u32() (Link erfordert Anmeldung), die es ermöglichen, diese Anweisung explizit aufzurufen.

Sie implementieren (source >> offset) & ((1 << n) - 1) C-Code: erhalten n kontinuierliche Bits aus source beginnend bei der offset bisschen. Hier ist eine vollständige Funktionsdefinition, die Grenzfälle behandelt:

#include <limits.h>

unsigned getbits(unsigned value, unsigned offset, unsigned n)
{
  const unsigned max_n = CHAR_BIT * sizeof(unsigned);
  if (offset >= max_n)
    return 0; /* value is padded with infinite zeros on the left */
  value >>= offset; /* drop offset bits */
  if (n >= max_n)
    return value; /* all  bits requested */
  const unsigned mask = (1u << n) - 1; /* n '1's */
  return value & mask;
}

Zum Beispiel zu bekommen 3 Stückchen ab 2273 (0b100011100001) beginnt um 5-th Bit, rufen Sie an getbits(2273, 5, 3)—es extrahiert 7 (0b111).

Angenommen, ich möchte die ersten 17 Bits des 32-Bit-Werts; was soll ich tun?

unsigned first_bits = value & ((1u << 17) - 1); // & 0x1ffff

Vorausgesetzt CHAR_BIT * sizeof(unsigned) ist 32 auf Ihrem System.

Ich nehme an, ich soll den Modulo-Operator verwenden, und ich habe es versucht und konnte die letzten 8 Bits und die letzten 16 Bits abrufen

unsigned last8bitsvalue  = value & ((1u <<  8) - 1); // & 0xff
unsigned last16bitsvalue = value & ((1u << 16) - 1); // & 0xffff

Wenn der Offset wie in allen Ihren Beispielen in der Frage immer Null ist, brauchen Sie den allgemeineren nicht getbits(). Es gibt einen speziellen CPU-Befehl BLSMSK, der hilft, die Maske zu berechnen ((1 << n) - 1).

Wenn Sie die X letzten Bits Ihrer Ganzzahl benötigen, verwenden Sie a binäre Maske :

unsigned last8bitsvalue=(32 bit integer) & 0xFF
unsigned last16bitsvalue=(32 bit integer) & 0xFFFF

Benutzeravatar von florind
Florind

Dies ist eine kürzere Variante der akzeptierten Antwort: Die folgende Funktion extrahiert die Bits von bis einschließlich, indem sie eine Bitmaske erstellt. Nach dem Anwenden einer UND-Logik auf die ursprüngliche Zahl wird das Ergebnis verschoben, sodass die Funktion nur die extrahierten Bits zurückgibt. Übersprungene Index-/Integritätsprüfungen zur Verdeutlichung.

uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to) 
{
  unsigned mask = ( (1<<(to-from+1))-1) << from;
  return (orig16BitWord & mask) >> from;
}

Bitweise UND Ihre Ganzzahl mit der Maske, die genau die Bits enthält, die Sie extrahieren möchten. Verschieben Sie dann das Ergebnis nach rechts, um die extrahierten Bits bei Bedarf neu zu positionieren.

unsigned int lowest_17_bits = myuint32 & 0x1FFFF;
unsigned int highest_17_bits = (myuint32 & (0x1FFFF << (32 - 17))) >> (32 - 17);

Bearbeiten: Letzteres positioniert die höchsten 17 Bits als die niedrigsten 17 neu; Dies kann nützlich sein, wenn Sie eine ganze Zahl „innerhalb“ einer größeren extrahieren müssen. Sie können die rechte Verschiebung weglassen (>>) falls dies nicht erwünscht ist.

1402760cookie-checkWie extrahiere ich bestimmte ‘n’ Bits einer 32-Bit-Ganzzahl ohne Vorzeichen in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy