Comment obtenir des données bit par bit à partir d'une valeur entière en C?

99

Je souhaite extraire des bits d'un nombre décimal.

Par exemple, 7 est le binaire 0111, et je veux obtenir 0 1 1 1 tous les bits stockés dans bool. Comment puis-je le faire?

OK, une boucle n'est pas une bonne option, puis-je faire autre chose pour cela?

Badr
la source

Réponses:

154

Si vous voulez le k-ième bit de n, alors faites

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

Ici, nous créons un masque, appliquons le masque à n, puis décalons à droite la valeur masquée pour obtenir exactement le bit que nous voulons. Nous pourrions l'écrire plus complètement comme:

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

Vous pouvez en savoir plus sur le masquage de bits ici .

Voici un programme:

#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");
}
index
la source
70
(n >> k) & 1est également valide et ne nécessite pas de calculer le masque car le masque est constant en raison du décalage avant le masquage au lieu de l'inverse.
Joe
@Joe pouvez-vous expliquer cela, peut-être dans une réponse, s'il vous plaît?
Dan Rosenstark
1
@Yar a prolongé un peu mon commentaire et ajouté une nouvelle réponse comme demandé
Joe
Lorsque vous utilisez des bits connus pour obtenir des informations (c'est-à-dire pour des protocoles réseau, tels que Websockets), la conversion des données sur un structpeut également être utile, car vous obtenez toutes les données requises en une seule opération.
Myst
@forefinger, pouvez-vous s'il vous plaît poster un exemple de sortie du code.
Ashish Ahuja
83

Comme demandé, j'ai décidé d'étendre mon commentaire sur la réponse de l'index à une réponse à part entière. Bien que sa réponse soit correcte, elle est inutilement complexe. De plus, toutes les réponses actuelles utilisent des ints signés pour représenter les valeurs. Ceci est dangereux, car le déplacement vers la droite des valeurs négatives est défini par l'implémentation (c'est-à-dire non portable) et le déplacement vers la gauche peut conduire à un comportement indéfini (voir cette question ).

En décalant vers la droite le bit souhaité dans la position de bit la moins significative, le masquage peut être effectué avec 1. Pas besoin de calculer une nouvelle valeur de masque pour chaque bit.

(n >> k) & 1

En tant que programme complet, calculer (puis imprimer) un tableau de valeurs à un seul bit:

#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);
}

En supposant que vous vouliez calculer tous les bits comme dans ce cas, et non un spécifique, la boucle peut être modifiée en

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

Cela modifie inputen place et permet ainsi l'utilisation d'un décalage de largeur constante d'un bit, ce qui peut être plus efficace sur certaines architectures.

Joe
la source
5

Voici une façon de procéder. Il en existe de nombreuses autres:

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

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

Il est difficile de comprendre pourquoi l'utilisation d'une boucle n'est pas souhaitée, mais il est assez facile de dérouler la boucle:

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));

Ou évaluer des expressions constantes dans les quatre dernières instructions:

b [0] =  0 != (v & 1);
b [1] =  0 != (v & 2);
b [2] =  0 != (v & 4);
b [3] =  0 != (v & 8);
marcher
la source
3

Voici une manière très simple de le faire;

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
la source
1

@prateek merci pour votre aide. J'ai réécrit la fonction avec des commentaires pour une utilisation dans un programme. Augmentez 8 pour plus de bits (jusqu'à 32 pour un entier).

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
la source
1

Si vous ne voulez pas de boucles, vous devrez l'écrire:

#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;
}

Comme démontré ici, cela fonctionne également dans un initialiseur.

wildplasser
la source
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
la source
0

En utilisant std::bitset

int value = 123;
std::bitset<sizeof(int)> bits(value);
std::cout <<bits.to_string();
Smit Ycyken
la source
C'est une méthode utile, mais il y a quelque chose qui ne va pas dans l'exemple. bitset <n>, n est le nombre de bits, donc l'utilisation de sizeof (int) est incorrecte.
Jerry Chou