3129 votes

Comment régler, effacer et basculer un seul bit ?

Comment régler, effacer et basculer un bit ?

90 votes

Lisez ça : graphiques.stanford.edu/~seander/bithacks.html et, quand tu auras maîtrisé ça, lis celui-là : realtimecollisiondetection.net/blog/?p=78

22 votes

Vous pourriez également être intéressé par le site The Bit Twiddler , Astuces pour la manipulation des bits y Les Algorithmes magiques agrégés .

4333voto

Jeremy Ruten Points 59989

Réglage d'un bit

Utilisez l'opérateur OU par bit ( | ) pour définir un bit.

number |= 1UL << n;

Cela fixera le n ème partie de number . n doit être égal à zéro, si vous souhaitez définir l'option 1 et ainsi de suite jusqu'à n-1 si vous voulez régler le n ement.

Utilice 1ULL si number est plus large que unsigned long ; la promotion de 1UL << n ne se produit qu'après avoir évalué 1UL << n où le comportement non défini consiste à décaler de plus de la largeur d'un long . Il en va de même pour tous les autres exemples.

Dégager un peu

Utilisez l'opérateur ET binaire ( & ) pour effacer un bit.

number &= ~(1UL << n);

Cela permettra d'effacer les n ème partie de number . Vous devez inverser la chaîne de bits avec l'opérateur bitwise NOT ( ~ ), puis ET.

Basculer un peu

L'opérateur XOR ( ^ ) peut être utilisé pour basculer un bit.

number ^= 1UL << n;

Cela fera basculer le n ème partie de number .

Vérifier un peu

Tu n'as pas demandé ça, mais je pourrais tout aussi bien l'ajouter.

Pour vérifier un bit, décalez le nombre n vers la droite, puis effectuez un ET bit à bit :

bit = (number >> n) & 1U;

Cela mettra la valeur de la n ème partie de number dans la variable bit .

Changer le n e bit à x

Définir le n e bit à l'un ou l'autre 1 o 0 peut être réalisé avec ce qui suit sur une implémentation C++ à complément à 2 :

number ^= (-x ^ number) & (1UL << n);

Bit n sera définie si x es 1 et effacé si x es 0 . Si x a une autre valeur, vous obtenez des déchets. x = !!x le rendra booléen à 0 ou 1.

Pour que cela soit indépendant du comportement de négation du complément à 2 (où -1 a tous les bits définis, contrairement à une implémentation C++ de complément à 1 ou de signe/magnitude), utilisez la négation non signée.

number ^= (-(unsigned long)x ^ number) & (1UL << n);

o

unsigned long newbit = !!x;    // Also booleanize to force 0 or 1
number ^= (-newbit ^ number) & (1UL << n);

C'est généralement une bonne idée d'utiliser des types non signés pour la manipulation portable des bits.

o

number = (number & ~(1UL << n)) | (x << n);

(number & ~(1UL << n)) effacera le n e bit et (x << n) définira le n e bit à x .

C'est aussi une bonne idée de ne pas copier/coller le code en général et beaucoup de gens utilisent des macros de préprocesseur (telles que la réponse du wiki communautaire plus bas ) ou une sorte d'encapsulation.

163 votes

Je voudrais noter que sur les plateformes qui ont un support natif pour le bit set/clear (ex, microcontrôleurs AVR), les compilateurs traduiront souvent 'myByte |= (1 << x)' en instructions natives bit set/clear chaque fois que x est une constante, ex : (1 << 5), ou const unsigned x = 5.

55 votes

Bit = nombre & (1 << x) ; ne mettra pas la valeur du bit x dans bit, sauf si bit a le type _Bool (<stdbool.h>). Sinon, bit = ! !(nombre & (1 << x)) ; va

3 votes

Ce genre de solutions ne fonctionne que lorsque la variable cible est de type intégral. Des solutions plus générales peuvent être mises en œuvre pour d'autres types de cibles utiles, comme les tableaux.

558voto

Loki Astari Points 116129

Utilisation de la bibliothèque standard C++ : std::bitset<N> .

Ou le Boost version : boost::dynamic_bitset .

Il n'est pas nécessaire d'en faire un :

#include <bitset>
#include <iostream>

int main()
{
    std::bitset<5> x;

    x[1] = 1;
    x[2] = 0;
    // Note x[0-4]  valid

    std::cout << x << std::endl;
}

[Alpha:] > ./a.out
00010

La version Boost permet un jeu de bits de taille d'exécution par rapport à un bibliothèque standard un jeu de bits dimensionné au moment de la compilation.

43 votes

+1. Non pas que std::bitset soit utilisable depuis le "C", mais comme l'auteur a étiqueté sa question avec "C++", AFAIK, votre réponse est la meilleure ici... std::vector<bool> est une autre solution, si on connaît ses avantages et ses inconvénients

1 votes

Bien joué, Martin ! Vous pouvez même utiliser un enum pour 'indexer' les bits : enum { cEngineOn, cDoorsOpen, cAircoOn } ; std::bitset< cNBBITS > mybits ; mybits[ cEngineOn ].set() ; const bool cbDoorOpen = mybits[ cDoorsOpen ] ; ...

0 votes

Parmi les réponses ici, je pense que c'est la meilleure façon de gérer les bits...mais je suppose que l'esprit de la question était de savoir comment manipuler les bits manuellement. quand même, +vote :)

285voto

Ferruccio Points 51508

L'autre option consiste à utiliser des champs de bits :

struct bits {
    unsigned int a:1;
    unsigned int b:1;
    unsigned int c:1;
};

struct bits mybits;

définit un champ de 3 bits (en fait, il s'agit de trois champs de 1 bit). Les opérations sur les bits sont maintenant un peu (haha) plus simples :

Pour activer ou désactiver un bit :

mybits.b = 1;
mybits.c = 0;

Pour basculer un peu :

mybits.a = !mybits.a;
mybits.b = ~mybits.b;
mybits.c ^= 1;  /* all work */

Je vérifie un peu :

if (mybits.c)  //if mybits.c is non zero the next line below will execute

Cela ne fonctionne qu'avec des champs de bits de taille fixe. Sinon, vous devez recourir aux techniques de manipulation des bits décrites dans les messages précédents.

82 votes

J'ai toujours trouvé que l'utilisation des champs de bits était une mauvaise idée. Vous n'avez aucun contrôle sur l'ordre dans lequel les bits sont alloués (du haut ou du bas), ce qui rend impossible la sérialisation de la valeur d'une manière stable/portable sauf bit par bit. Il est également impossible de mélanger l'arithmétique des bits bricolés avec les champs de bits, par exemple en créant un masque qui teste plusieurs bits à la fois. Vous pouvez bien sûr utiliser && et espérer que le compilateur l'optimisera correctement...

45 votes

Les champs de bits sont mauvais à bien des égards, je pourrais presque écrire un livre à ce sujet. En fait, j'ai presque dû le faire pour un programme de champs binaires qui devait être conforme à la norme MISRA-C. MISRA-C exige que tout comportement défini par l'implémentation soit documenté, et j'ai donc fini par écrire un essai sur tout ce qui peut mal tourner dans les champs de bits. Ordre des bits, endianess, bits de remplissage, octets de remplissage, divers autres problèmes d'alignement, conversions de types implicites et explicites vers et depuis un champ de bits, UB si int n'est pas utilisé et ainsi de suite. Au lieu de cela, utilisez des opérateurs binaires pour moins de bogues et un code portable. Les champs de bits sont complètement redondants.

52 votes

Comme la plupart des fonctionnalités du langage, les champs de bits peuvent être utilisés correctement ou abusivement. Si vous devez regrouper plusieurs petites valeurs dans un seul int, les champs de bits peuvent être très utiles. D'un autre côté, si vous commencez à faire des suppositions sur la façon dont les champs de bits correspondent aux int qu'ils contiennent, vous vous exposez à des problèmes.

251voto

Steve Karg Points 11

J'utilise des macros définies dans un fichier d'en-tête pour gérer l'activation et la désactivation des bits :

/* a=target variable, b=bit number to act upon 0-n */
#define BIT_SET(a,b) ((a) |= (1ULL<<(b)))
#define BIT_CLEAR(a,b) ((a) &= ~(1ULL<<(b)))
#define BIT_FLIP(a,b) ((a) ^= (1ULL<<(b)))
#define BIT_CHECK(a,b) (!!((a) & (1ULL<<(b))))        // '!!' to make sure this returns 0 or 1

/* x=target variable, y=mask */
#define BITMASK_SET(x,y) ((x) |= (y))
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
#define BITMASK_FLIP(x,y) ((x) ^= (y))
#define BITMASK_CHECK_ALL(x,y) (!(~(x) & (y)))
#define BITMASK_CHECK_ANY(x,y) ((x) & (y))

20 votes

Je sais que ce message date d'il y a 5 ans, mais il n'y a pas de duplication d'arguments dans ces macros, Dan.

15 votes

BITMASK_CHECK(x,y) ((x) & (y)) doit être ((x) & (y)) == (y) sinon il renvoie un résultat incorrect sur le masque multibit (ex. 5 vs. 3 ) /*Bonjour à tous les fossoyeurs :)*/

9 votes

1 devrait être (uintmax_t)1 ou similaire au cas où quelqu'un essaierait d'utiliser ces macros sur une long ou un type plus grand

143voto

dmckee Points 50318

Il est parfois utile d'utiliser un enum a nom les bits :

enum ThingFlags = {
  ThingMask  = 0x0000,
  ThingFlag0 = 1 << 0,
  ThingFlag1 = 1 << 1,
  ThingError = 1 << 8,
}

Utilisez ensuite le noms plus tard. Par exemple, écrivez

thingstate |= ThingFlag1;
thingstate &= ~ThingFlag0;
if (thing & ThingError) {...}

pour définir, effacer et tester. De cette façon, vous cachez les chiffres magiques du reste de votre code.

Sinon, j'approuve la solution de Jeremy.

2 votes

Vous pouvez aussi faire un clearbits() au lieu de la fonction &= ~ . Pourquoi utilisez-vous un enum pour cela ? Je pensais que c'était pour créer un tas de variables uniques avec une valeur arbitraire cachée, mais vous attribuez une valeur définie à chacune d'entre elles. Quel est donc l'avantage par rapport à une simple définition de variables ?

5 votes

@endolith : L'utilisation de enum pour des ensembles de constantes apparentées remonte à un long moment dans la programmation en c. Je soupçonne qu'avec les compilateurs modernes, le seul avantage par rapport à la fonction const short ou autre, c'est qu'ils sont explicitement regroupés. Et quand vous les voulez pour quelque chose autre que les bitmasks, vous bénéficiez de la numérotation automatique. En c++, bien sûr, ils forment également des types distincts, ce qui vous donne un petit plus en matière de vérification statique des erreurs.

1 votes

Vous vous retrouverez avec des constantes enum non définies si vous ne définissez pas une constante pour chacune des valeurs possibles des bits. Quel est le enum ThingFlags valeur pour ThingError|ThingFlag1 par exemple ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X