Wie erhalte ich bitweise Daten von einem ganzzahligen Wert in C?

99

Ich möchte Bits einer Dezimalzahl extrahieren.

Zum Beispiel ist 7 binär 0111, und ich möchte 0 1 1 1 alle in bool gespeicherten Bits erhalten. Wie kann ich das machen?

OK, eine Schleife ist keine gute Option. Kann ich etwas anderes dafür tun?

Badr
quelle

Antworten:

152

Wenn Sie das k-te Bit von n wollen, dann tun Sie es

(n & ( 1 << k )) >> k

Hier erstellen wir eine Maske, wenden die Maske auf n an und verschieben dann den maskierten Wert nach rechts, um genau das gewünschte Bit zu erhalten. Wir könnten es ausführlicher schreiben als:

    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;

Weitere Informationen zur Bitmaskierung finden Sie hier .

Hier ist ein Programm:

#include <stdio.h>
#include <stdlib.h>

int *get_bits(int n, int bitswanted){
  int *bits = malloc(sizeof(int) * bitswanted);

  int k;
  for(k=0; k<bitswanted; k++){
    int mask =  1 << k;
    int masked_n = n & mask;
    int thebit = masked_n >> k;
    bits[k] = thebit;
  }

  return bits;
}

int main(){
  int n=7;

  int  bitswanted = 5;

  int *bits = get_bits(n, bitswanted);

  printf("%d = ", n);

  int i;
  for(i=bitswanted-1; i>=0;i--){
    printf("%d ", bits[i]);
  }

  printf("\n");
}
Zeigefinger
quelle
70
(n >> k) & 1ist gleichermaßen gültig und erfordert keine Berechnung der Maske, da die Maske aufgrund von Verschiebungen vor dem Maskieren konstant ist und nicht umgekehrt.
Joe
@ Joe kannst du das erklären, vielleicht in einer Antwort, bitte?
Dan Rosenstark
1
@Yar erweiterte meinen Kommentar ein wenig und fügte eine neue Antwort wie gewünscht hinzu
Joe
Wenn Sie bekannte Informationsbits verwenden (z. B. für Netzwerkprotokolle wie Websockets), structkann es auch nützlich sein, die Daten auf a zu übertragen, da Sie alle erforderlichen Daten mit einer einzigen Operation erhalten.
Myst
@forefinger, können Sie bitte eine Beispielausgabe des Codes posten.
Ashish Ahuja
81

Wie gewünscht, habe ich beschlossen, meinen Kommentar zur Antwort des Zeigefingers auf eine vollständige Antwort auszudehnen. Obwohl seine Antwort richtig ist, ist sie unnötig komplex. Darüber hinaus verwenden alle aktuellen Antworten vorzeichenbehaftete ints, um die Werte darzustellen. Dies ist gefährlich, da die Rechtsverschiebung negativer Werte implementierungsdefiniert ist (dh nicht portierbar ist) und die Linksverschiebung zu undefiniertem Verhalten führen kann (siehe diese Frage ).

Durch Verschieben des gewünschten Bits nach rechts in die niedrigstwertige Bitposition kann eine Maskierung durchgeführt werden 1. Es ist nicht erforderlich, für jedes Bit einen neuen Maskenwert zu berechnen.

(n >> k) & 1

Berechnen (und anschließend drucken) eines Arrays von Einzelbitwerten als vollständiges Programm:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv)
{
    unsigned
        input = 0b0111u,
        n_bits = 4u,
        *bits = (unsigned*)malloc(sizeof(unsigned) * n_bits),
        bit = 0;

    for(bit = 0; bit < n_bits; ++bit)
        bits[bit] = (input >> bit) & 1;

    for(bit = n_bits; bit--;)
        printf("%u", bits[bit]);
    printf("\n");

    free(bits);
}

Angenommen, Sie möchten alle Bits wie in diesem Fall berechnen und nicht ein bestimmtes, kann die Schleife weiter in geändert werden

for(bit = 0; bit < n_bits; ++bit, input >>= 1)
    bits[bit] = input & 1;

Dies ändert sich inputan Ort und Stelle und ermöglicht dadurch die Verwendung einer Einzelbitverschiebung mit konstanter Breite, die bei einigen Architekturen effizienter sein kann.

Joe
quelle
5

Hier ist eine Möglichkeit, dies zu tun: Es gibt viele andere:

bool b[4];
int v = 7;  // number to dissect

for (int j = 0;  j < 4;  ++j)
   b [j] =  0 != (v & (1 << j));

Es ist schwer zu verstehen, warum die Verwendung einer Schleife nicht erwünscht ist, aber es ist einfach genug, die Schleife abzuwickeln:

bool b[4];
int v = 7;  // number to dissect

b [0] =  0 != (v & (1 << 0));
b [1] =  0 != (v & (1 << 1));
b [2] =  0 != (v & (1 << 2));
b [3] =  0 != (v & (1 << 3));

Oder konstante Ausdrücke in den letzten vier Anweisungen auswerten:

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);
Wallyk
quelle
3

Hier ist eine sehr einfache Möglichkeit, dies zu tun.

int main()
{
    int s=7,l=1;
    vector <bool> v;
    v.clear();
    while (l <= 4)
    {
        v.push_back(s%2);
        s /= 2;
        l++;
    }
    for (l=(v.size()-1); l >= 0; l--)
    {
        cout<<v[l]<<" ";
    }
    return 0;
}
d3vdpro
quelle
1

@prateek danke für deine Hilfe. Ich habe die Funktion mit Kommentaren zur Verwendung in einem Programm umgeschrieben. Erhöhen Sie 8 für weitere Bits (bis zu 32 für eine Ganzzahl).

std::vector <bool> bits_from_int (int integer)    // discern which bits of PLC codes are true
{
    std::vector <bool> bool_bits;

    // continously divide the integer by 2, if there is no remainder, the bit is 1, else it's 0
    for (int i = 0; i < 8; i++)
    {
        bool_bits.push_back (integer%2);    // remainder of dividing by 2
        integer /= 2;    // integer equals itself divided by 2
    }

    return bool_bits;
}
xinthose
quelle
1

Wenn Sie keine Schleifen möchten, müssen Sie diese ausschreiben:

#include <stdio.h>
#include <stdbool.h>

int main(void)
{
    int num = 7;

    #if 0
        bool arr[4] = { (num&1) ?true: false, (num&2) ?true: false, (num&4) ?true: false, (num&8) ?true: false };
    #else
        #define BTB(v,i) ((v) & (1u << (i))) ? true : false
        bool arr[4] = { BTB(num,0), BTB(num,1), BTB(num,2), BTB(num,3)};
        #undef BTB
    #endif

    printf("%d %d %d %d\n", arr[3], arr[2], arr[1], arr[0]);

    return 0;
}

Wie hier gezeigt, funktioniert dies auch in einem Initialisierer.

Wildplasser
quelle
0
#include <stdio.h>

int main(void)
{
    int number = 7; /* signed */
    int vbool[8 * sizeof(int)];
    int i;
        for (i = 0; i < 8 * sizeof(int); i++)
        {
            vbool[i] = number<<i < 0;   
            printf("%d", vbool[i]);
        }
    return 0;
}
anon
quelle
0

Verwenden von std::bitset

int value = 123;
std::bitset<sizeof(int)> bits(value);
std::cout <<bits.to_string();
Smit Ycyken
quelle
Es ist eine nützliche Methode, aber im Beispiel stimmt etwas nicht. Bitset <n>, n ist die Anzahl der Bits, daher ist die Verwendung von sizeof (int) falsch.
Jerry Chou