Comment extraire des bits 'n' spécifiques d'un entier non signé 32 bits en C?

Quelqu'un pourrait-il me dire comment extraire des bits spécifiques 'n' d'un entier non signé 32 bits dans C.

Par exemple, disons que je veux les 17 premiers bits de la valeur de 32 bits; que dois-je faire?
Je suppose que je suis censé utiliser l'opérateur module et je l'ai essayé et j'ai pu obtenir les 8 derniers bits et les 16 derniers bits comme

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

Est-ce correct? Y a-t-il un moyen meilleur et plus efficace de le faire?

28
c
demandé sur Jonathan Leffler 2011-11-04 19:28:09

8 réponses

Si vous voulez les n bits spécifiques ensuite, vous pouvez d'abord créer un masque de bits, puis AND avec votre numéro souhaité bits.

Fonction Simple pour créer un masque du bit a au bit B.

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

   return r;
}

Vous devriez vérifier que a

Si vous voulez des bits 12 à 16 appelez la fonction, puis simplement & (logique et) r avec votre numéro N

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

Si vous le souhaitez, vous pouvez déplacer le résultat. J'espère que cela aide

25
répondu pnezis 2016-10-28 11:22:32

Au lieu de penser comme "extraire", j'aime penser comme "isoler". Une fois que les bits souhaités sont isolés, vous pouvez faire ce que vous voulez avec eux.

Pour isoler n'importe quel ensemble de bits, appliquez un masque et.

Si vous voulez les X derniers bits d'une valeur, il y a une astuce simple qui peut être utilisée.

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

Si vous voulez isoler une série de x bits au milieu de 'value' à partir de 'startBit'...

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

J'espère que cela aide.

38
répondu Sparky 2011-11-04 15:58:44

Module fonctionne pour obtenir des bits de fond (seulement), bien que je pense que value & 0x1ffff exprime "prendre les 17 bits de fond" plus directement que value % 131072, et est donc plus facile à comprendre.

Les 17 premiers bits d'une valeur non signée 32 bits seraient value & 0xffff8000 (Si vous voulez qu'ils restent dans leurs positions en haut), ou value >> 15 Si vous voulez que les 17 premiers bits de la valeur soient dans les 17 derniers bits du résultat.

8
répondu Steve Jessop 2011-11-04 15:31:35

Si vous avez besoin des X derniers bits de votre entier, utilisez un masque binaire :

unsigned last8bitsvalue=(32 bit integer) & 0xFF
unsigned last16bitsvalue=(32 bit integer) & 0xFFFF
6
répondu Cédric Julien 2011-11-04 15:33:59

Bitwise et votre entier avec le masque ayant exactement les bits définis que vous voulez extraire. Ensuite, déplacez le résultat à droite pour repositionner les bits extraits si vous le souhaitez.

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

Edit: ce dernier repositionne les 17 bits les plus élevés comme les 17 les plus bas; cela peut être utile si vous avez besoin d'extraire un entier de "dans" un plus grand. Vous pouvez omettre le bon décalage (>>) si cela n'est pas souhaité.

4
répondu Arkku 2011-11-04 15:38:39

Il existe une seule instruction bextr (bit field extract (with register)) x86 sur les processeurs Intel et AMD et UBFX sur le bras. Il existe des fonctions intrinsèques telles que _bextr_u32() (link nécessite une connexion) qui permettent d'invoquer explicitement cette instruction.

Ils implémentent (source >> offset) & ((1 << n) - 1) code C: get n bits continus à partir de source en commençant par le offset bit. Voici une définition de fonction complète qui gère les cas de bord:

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

Par exemple, Pour obtenir 3 bits à partir de 2273 (0b100011100001) au départ de 5-ème bit, appel getbits(2273, 5, 3)-il extrait 7 (0b111).

Par exemple, disons que je veux les 17 premiers bits de la valeur de 32 bits; que dois-je faire?

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

En Supposant que CHAR_BIT * sizeof(unsigned) est 32 sur votre système.

Je présume que je suis censé utiliser l'opérateur module et je l'ai essayé et j'ai pu obtenir les 8 derniers bits et les 16 derniers bits

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

Si le décalage est toujours nul comme dans tous vos exemples question alors vous n'avez pas besoin du plus général getbits(). Il y a une instruction cpu spéciale BLSMSK qui aide à calculer le masque ((1 << n) - 1).

3
répondu jfs 2017-05-23 12:10:45

C'est une variation plus brève de la réponse acceptée: la fonction ci-dessous extrait les bits de-à inclusive en créant un masque de bits. Après avoir appliqué une logique et sur le nombre d'origine, le résultat est décalé de sorte que la fonction ne renvoie que les bits extraits. Contrôles d'index/intégrité ignorés pour plus de clarté.

uint16_t extractInt(uint16_t orig16BitWord, unsigned from, unsigned to) 
{
  unsigned mask = ( (1<<(to-from+1))-1) << from;
  return (orig16BitWord & mask) >> from;
}
2
répondu florind 2015-06-08 09:24:46
#define GENERAL__GET_BITS_FROM_U8(source,lsb,msb) \
    ((uint8_t)((source) & \
        ((uint8_t)(((uint8_t)(0xFF >> ((uint8_t)(7-((uint8_t)(msb) & 7))))) & \
             ((uint8_t)(0xFF << ((uint8_t)(lsb) & 7)))))))

#define GENERAL__GET_BITS_FROM_U16(source,lsb,msb) \
    ((uint16_t)((source) & \
        ((uint16_t)(((uint16_t)(0xFFFF >> ((uint8_t)(15-((uint8_t)(msb) & 15))))) & \
            ((uint16_t)(0xFFFF << ((uint8_t)(lsb) & 15)))))))

#define GENERAL__GET_BITS_FROM_U32(source,lsb,msb) \
    ((uint32_t)((source) & \
        ((uint32_t)(((uint32_t)(0xFFFFFFFF >> ((uint8_t)(31-((uint8_t)(msb) & 31))))) & \
            ((uint32_t)(0xFFFFFFFF << ((uint8_t)(lsb) & 31)))))))
-1
répondu jeboo 2015-04-16 14:17:15