Comment définissez-vous, claire, et de basculer d'un seul bit?
Comment définissez-vous, claire, et bascule un peu?
- lire ceci: graphics.stanford.edu/~seander/bithacks.html et, quand vous allez à la maîtrise de cette, de lire celui-ci: realtimecollisiondetection.net/blog/?p=78
- Vous pourriez également être intéressé dans la vérification des Le Peu Twiddler, Peu Tourner les Hacks, et Le total de la Magie des Algorithmes.
- Je peux facilement imaginer que ce n'était pas pour la question elle-même, mais pour la fraie un très guide de référence utile. Étant donné que je suis arrivé ici quand j'ai besoin d'un peu d'informations, de toute façon.
- il a assez d'importance pour le C++ pour être étiqueté comme tel. C'est un historique de la question avec beaucoup de circulation et le C++ balise aider les collègues intéressés programmeurs trouver par une recherche google.
- Je suis en supposant que vous savez comment faire pour activer/désactiver les bits dans un octet? (E. g., à l'aide de hex?)
- stackoverflow.com/questions/11815894/...
- Essayer QBitArray: doc.qt.io/qt-5/qbitarray.html
- google.com/...
Vous devez vous connecter pour publier un commentaire.
Réglage un peu
Utiliser l'opérateur or (
|
) pour définir un bit.Qui va définir la
n
- ième bit denumber
.n
doit être égale à zéro, si vous souhaitez définir la1
st bits et ainsi de suite jusqu'àn-1
, si vous souhaitez définir lan
- ième bit.Utilisation
1ULL
sinumber
est plus large queunsigned long
; la promotion de la1UL << n
n'arrive pas jusqu'à ce que après l'évaluation de1UL << n
où c'est un comportement indéterminé se déplacent de plus que la largeur d'unlong
. La même chose s'applique à tout le reste des exemples.De compensation un peu
Utiliser le bit à bit ET de l'opérateur (
&
) pour effacer un peu.Qui va effacer la
n
- ième bit denumber
. Vous devez inverser la chaîne de bits avec le not au niveau du bit opérateur (~
), ET puis il.Basculer un peu
De l'opérateur XOR (
^
) peut être utilisée pour activer un peu.Qui fera basculer le
n
- ième bit denumber
.Vérifier un peu
Vous n'avez pas demandé, mais je peux bien ajouter.
Pour vérifier un peu, maj le nombre n à droite, puis au niveau du bit ET c':
Qui va mettre la valeur de la
n
- ième bit denumber
dans la variablebit
.La modification de la n - ième bit de x
Réglage de la
n
ème bit soit1
ou0
peut être réalisé par la suite un complément de 2 implémentation C++:Peu
n
sera fixé six
est1
, et effacé six
est0
. Six
a une autre valeur, vous obtenez des ordures.x = !!x
sera booleanize à 0 ou 1.Pour faire de ce indépendant de 2 en complément à la négation de comportement (où
-1
a tous les bits définis, contrairement à un 1 de les compléter ou de les signer et l'ampleur implémentation C++), utiliser unsigned négation.ou
Il est généralement une bonne idée d'utiliser unsigned types de portable de manipulation de bits.
ou
(number & ~(1UL << n))
sera clairement len
- ième bit et(x << n)
va définir len
- ième bit dex
.Il est aussi généralement une bonne idée de ne pas copier/coller le code en général et donc beaucoup de gens utilisent les macros du préprocesseur (comme le wiki de la communauté réponse plus bas) ou une sorte d'encapsulation.
number
est plus large queint
bit = (number >> x) & 1
1
est unint
littéral, qui est signé. De sorte que toutes les opérations à opérer sur des nombres signés, ce qui n'est pas bien défini par les normes. Les normes ne garantit pas en complément à deux ou décalage de sorte qu'il est préférable d'utiliser1U
.unsigned long long
dans la taille de toute façon... il y a peut être mise en œuvre-les extensions définies comme__int128
. Pour être ultra-sécuritaire(uintmax_t)1 << x
number = number & ~(1 << n) | (x << n);
pour Changer le n-ième bit de x.number
est plus grande queint
etn
est supérieur ou égal au nombre de bits dans unint
. Il invoque même comportement indéfini dans ce cas.number = number & ~((uintmax_t)1 << n) | ((uintmax_t)x << n);
est une expression générique qui devrait fonctionner pour toutes les tailles denumber
mais peut générer laid et inefficace code pour les petites tailles.-x
n'est pas sûr car le C standard permet des entiers signés de l'être (par exemple) de connexion de l'ampleur, les compléter, ou tout autre système qui peut exprimer la gamme nécessaire, ce qui signifie que-x
est pas doivent être les mêmes que(~x) + 1
. Ce n'est pas que les grandes d'un accord sur les architectures modernes, mais vous ne savez jamais ce que suffisamment habile compilateur optimisant allez faire avec votre code.~
au lieu!
?~
) inverse tous les bits, de sorte~0xFFF0FFFF
est0x000F0000
. Boolean pas (!
) donne 0 si la valeur est différente de zéro ou 1 si la valeur est zéro, donc!0xFFF0FFFF
est0x00000000
.-1
est0b1111..1110
. (Tout est-0
). C++ permet également le signe et l'ampleur entier représentations, où-x
juste à l'inverse le bit de signe. J'ai mis à jour cette réponse pour le signaler. C'est tout à fait bien si vous ne cible que les 2 en complément à C++ implémentations. Ce n'est pas UB, c'est simplement la mise en œuvre définies, de sorte qu'il est nécessaire pour travailler correctement sur les implémentations de la définition des nombres entiers signés en tant que complément de 2. J'ai aussi changé les constantes de1UL
, avec une note qui1ULL
peut être nécessaire.-(unsigned long)x
qui serait également pas de côté l'signé-représentation entière. (unsigned base 2 matchs 2 de complément sémantique.) Mais il ne fonctionne correctement que six
est 0 ou 1. N'oubliez pas que nous sommes en positionnant le bitn
àx
.0U - 1U
-> tout-petits. Comment est-il maintenant? J'ai essayé de garder la réponse simple. Je ne mentionnez que vous devrez peut-être booleanize avec!!x
. Si c'était ma propre réponse, je pourrais insérer plus de texte sur utilisant toujours pas signé, mais je suis juste le maintien de cette vieille réponse canonique. (Jeremy, j'espère que vous aimez les modifications, vous pouvez éditer pour mettre mes modifications dans vos propres mots ou quoi que ce soit que vous voulez dire près de 9 ans plus tard.)n
- ième bit dex
section a été ajoutée par un autre de la 3e partie modifier, et n'était pas Jeremy travail en premier lieu.À l'aide de la Bibliothèque C++ Standard:
std::bitset<N>
.Ou la Boost version:
boost::dynamic_bitset
.Il n'est pas nécessaire de rouler vos propres:
Le Boost version permet une exécution de taille bitset comparé avec un la bibliothèque standard au moment de la compilation de la taille d'bitset.
sudo apt-get install boost-devel
L'autre option est d'utiliser des champs de bits:
définit 3-champ de bits (en fait, c'est trois 1 bit felds). Les opérations sur les bits maintenant devenu un peu (haha) de plus simple:
De mettre ou d'enlever un peu:
Pour alterner un peu:
Vérifier un peu:
Cela fonctionne uniquement avec la taille fixe de champs de bits. Sinon, vous devrez recourir à la bit-se tourner les techniques décrites dans les messages précédents.
sizeof(mybits)
, j'obtiens 12 (c'est à dire la taille de troisints
). Est-ce l'espace alloué dans la mémoire ou certains bug dans lesizeof
fonction?gcc
version 4.4.5struct
peut être mis à l'intérieur d'un (généralement anonymes)union
avec un entier, etc. Elle fonctionne. (Je me rends compte que c'est un vieux thread btw)- Je utiliser les macros définies dans un fichier d'en-tête pour gérer l'ensemble de peu de et claire:
BITMASK_CHECK(x,y) ((x) & (y))
doit être((x) & (y)) == (y)
sinon il renvoie un résultat incorrect sur multibit masque (ex.5
vs3
) /*Bonjour à tous les fossoyeurs :)*/1
devrait être(uintmax_t)1
ou similaire dans le cas où quelqu'un essaie d'utiliser ces macros sur unlong
ou plus type1ULL
œuvres ainsi que(uintmax_t)
sur la plupart des implémentations.BITMASK_CHECK_ALL(x,y)
peut être mis en œuvre!~((~(y))|(x))
!(~(x) & (y))
Il est parfois utile d'utiliser un
enum
à nom les bits:Puis utilisez le noms plus tard. I. e. écrire
d'ensemble, claire et test. De cette façon, vous masquer les numéros de magie du reste de votre code.
Que je ne cautionne Jeremy la solution.
clearbits()
fonction au lieu de&= ~
. Pourquoi êtes-vous à l'aide d'un enum pour cela? Je pensais que ceux qui étaient pour la création d'un groupe unique de variables cachées valeur arbitraire, mais vous assignez une valeur définie pour chacun d'eux. Alors, quel est l'avantage vs juste de les définir comme des variables?enum
s pour des ensembles de constantes remonte un long chemin en c programmation. Je soupçonne qu'avec les compilateurs modernes le seul avantage surconst short
ou que ce soit, c'est qu'ils sont explicitement regroupés. Quand vous voulez quelque chose de autres que les masques de bits, vous obtenez la numérotation automatique. En c++, bien sûr, ils forment aussi des types distincts qui vous donne un peu d'extras erreur statique de contrôle.enum ThingFlags
valeur pourThingError|ThingFlag1
, par exemple?int
. Cela peut causer toutes sortes de bogues subtils en raison de l'implicite entier de promotion de la ou des opérations bit à bit sur les types signés.thingstate = ThingFlag1 >> 1
, par exemple, invoquer la mise en œuvre définies par le comportement.thingstate = (ThingFlag1 >> x) << y
peut invoquer un comportement indéfini. Et ainsi de suite. Pour être sûr, toujours jeté un type non signé.enum My16Bits: unsigned short { ... };
De snip-c.zip's bitops.h:
OK, nous allons analyser les choses...
L'expression courante que vous semblez avoir des problèmes avec de tout cela est l' "(1L << (position))". Tout cela n'est de créer un masque avec un seul bit sur
et qui va travailler avec tout type entier. La "position" argument spécifie le
la position où vous souhaitez que le bit. Si position==0, alors cette expression
évaluer:
Si position==8, il va évaluer à:
En d'autres termes, il crée simplement un champ de 0 par un 1 à la position spécifiée
position. La seule partie délicate est dans le BitClr() macro où nous avons besoin de définir
un seul bit à 0 dans un champ de 1. Ceci est accompli en utilisant le 1
en complément de la même expression, tel que désigné par le tilde (~) de l'opérateur.
Une fois que le masque est créé, il est appliqué à l'argument comme vous le suggérez,
par l'utilisation de la bit-à-bit " et " (&), ou (|), et xor (^) les opérateurs. Puisque le masque
est de type long, les macros fonctionnent tout aussi bien sur le char, short de, int,
ou long.
La ligne de fond est que c'est une solution générale à toute une classe d'
problèmes. Il est, bien sûr, possible et même approprié pour réécrire l'
l'équivalent de l'un de ces macros explicite de valeurs de masque à chaque fois que vous
besoin d'un, mais pourquoi faire? Rappelez-vous, la substitution macro se produit dans le
préprocesseur et donc le code généré sera de refléter le fait que les valeurs
sont considérés comme constants par le compilateur - dire qu'elle est tout aussi efficace à utiliser
la généralisation des macros à "réinventer la roue" à chaque fois que vous devez faire
de manipulation de bits.
Pas convaincu? Voici un code de test - j'ai utilisé Watcom C avec une optimisation complète
et sans l'aide de _cdecl de sorte que le montant de démontage serait aussi propre que
possible:
----[ TEST.C ]----------------------------------------------------------------
----[ TEST.OUT (démonté) ]-----------------------------------------------
----[ finis ]-----------------------------------------------------------------
arg
estlong long
.1L
doit être la plus large possible, donc(uintmax_t)1
. (Vous pourriez sortir avec1ull
)Utiliser les opérateurs au niveau du bit:
&
|
Pour définir dernier bit dans
000b
:Pour vérifier le dernier bit dans
foo
:Pour effacer la dernière bits dans
foo
:J'ai utilisé
XXXb
pour plus de clarté. Vous aurez probablement à travailler avec de représentation HEXADÉCIMALE, en fonction de la structure de données dans laquelle vous êtes d'emballage bits.foo = foo ^ MY_MASK
foo = foo & ~MY_MASK
Pour le débutant que je voudrais expliquer un peu plus avec un exemple:
Exemple:
La
&
opérateur permet de vérifier le bit:Basculer ou Pivoter:
|
opérateur: définir le bitVoici mon préféré bits arithmétique macro qui fonctionne pour n'importe quel type d'entier non signé de tableau à partir de
unsigned char
jusqu'àsize_t
(qui est le type le plus grand qui devrait être efficace de travailler avec):Pour définir un bit:
Pour effacer un peu:
Pour alterner un peu:
Pour tester un peu:
etc.
BITOP(array, bit++, |=);
dans une boucle ne sera probablement pas faire ce que l'appelant veut.BITCELL(a,b) |= BITMASK(a,b);
(à la fois prendrea
comme un argument pour déterminer la taille, mais ce dernier ne serait jamais évaluera
puisqu'il n'apparaît que danssizeof
).(size_t)
cast semblent être là que pour assurer un unsigned math avec%
. Pourrait(unsigned)
là.(size_t)(b)/(8*sizeof *(a))
inutilement pourrait réduireb
avant la division. Seulement un problème de très grande peu de tableaux. Encore une macro intéressante.Que c'est marqué "embedded" je vais supposer que vous êtes à l'aide d'un microcontrôleur. Toutes les suggestions ci-dessus sont valables & travail (lecture-modification-écriture, les syndicats, les structures, etc.).
Cependant, au cours d'un épisode de l'oscilloscope à base de débogage, j'ai été très surpris de constater que ces méthodes ont une surcharge considérable dans les cycles CPU par rapport à l'écriture d'une valeur directement à la micro PORTnSET /PORTnCLEAR registres qui fait une réelle différence, là où il y a des boucles serrées /haute fréquence ISR du basculement pins.
Pour ceux qui ne connaissent pas: Dans mon exemple, le micro dispose d'un général de pin-registre d'état PORTn qui reflète les broches de sortie, ce faisant, PORTn |= BIT_TO_SET résultats en lecture-modification-écriture dans ce registre. Cependant, la PORTnSET /PORTnCLEAR registres de prendre un " 1 " pour dire "s'il vous plaît faire ce bit 1" () ou "s'il vous plaît faire ce bit à zéro" (CLAIR) et un " 0 " dans le sens de "laisser la broche seul". donc, vous vous retrouvez avec deux adresses de port en fonction de si vous êtes activer ou de désactiver le bit (pas toujours pratique), mais un beaucoup de réaction plus rapide et plus petit assemblés code.
volatile
et, par conséquent, le compilateur est pas en mesure d'effectuer toutes les optimisations sur le code de l'implication de ces registres. Par conséquent, il est de bonne pratique de démonter ce type de code et de voir comment il s'est avéré sur l'assembleur niveau.Le champ de bits approche a d'autres avantages dans le sous-arena. Vous pouvez définir une structure que les cartes directement sur les bits dans un registre hardware.
Vous devez être conscient du bit afin d'emballage - je pense que c'est le MSB en premier, mais cela peut être dépendant de l'implémentation. Aussi, vérifiez comment votre compilateur gestionnaires des champs de traverser les limites d'octets.
Vous pouvez alors lire, d'écrire, de tester les différentes valeurs qu'avant.
Vérifier un peu à un emplacement arbitraire dans une variable de type arbitraire:
Exemple d'utilisation:
Notes:
Il est conçu pour être rapide (compte tenu de sa souplesse) et non branchu. Il en résulte efficace machine SPARC code lors de la compilation Sun Studio 8; j'ai aussi testé à l'aide de MSVC++ 2008 sur amd64. Il est possible de faire de même, les macros pour le réglage et la compensation de bits. La principale différence de cette solution par rapport à beaucoup d'autres ici, c'est que cela fonctionne pour n'importe quel endroit dans pratiquement n'importe quel type de variable.
Plus générale, pour arbitraire de la taille des bitmaps:
CHAR_BIT
est déjà défini parlimits.h
, vous n'avez pas besoin de mettre dans votre propreBITS
(et en fait, vous rendre votre code pire par le faire)Ce programme est de changer toutes les données bits de 0 à 1 ou de 1 à 0:
Si vous faites beaucoup de bits à vous tourner, vous pourriez vouloir utiliser des masques qui va rendre la chose plus rapidement. Les fonctions suivantes sont très rapides et sont encore souples (ils permettent peu tourner en peu de cartes de n'importe quelle taille).
Note, pour définir les bits 'n' dans un de 16 bits en entier de la manière suivante:
C'est à vous pour s'assurer que le nombre de bits est dans la plage de bits de la carte que vous passez. Notez que pour little endian processeurs d'octets, de mots, dword, qwords, etc., carte correctement les uns aux autres dans la mémoire (principale raison pour laquelle little endian processeurs sont "mieux" qu'big-endian processeurs, ah, je sens la flamme de la guerre à venir sur...).
Utiliser ceci:
Expansion sur le
bitset
réponse:Si vous souhaitez effectuer ce fonctionnement avec programmation en C dans le noyau Linux alors je vous suggérons d'utiliser la norme Api du noyau Linux.
Voir https://www.kernel.org/doc/htmldocs/kernel-api/ch02s03.html
Remarque: Ici, l'ensemble de l'opération se déroule en une seule étape. Donc, ces tous sont garantis pour être atomique même sur SMP ordinateurs et sont utiles
pour garder la cohérence de l'ensemble des processeurs.
Visual C 2010, et peut-être beaucoup d'autres compilateurs, ont un soutien direct pour les opérations sur les bits intégré. Étonnamment, cela fonctionne, même le
sizeof()
opérateur fonctionne correctement.Donc, à votre question,
IsGph[i] =1
, ouIsGph[i] =0
effectuez le réglage et la compensation de booléens facile.De trouver des caractères non imprimables:
Remarque il n'y a rien de "spécial" à propos de ce code. Il traite un peu comme un entier qui, techniquement, il est. Un bit à 1 entier qui peut contenir de 2 les valeurs, et les 2 valeurs seulement.
Une fois, j'ai utilisé cette approche pour trouver des doublons de dossiers d'emprunt, où loan_number était le ISAM clé, en utilisant les 6 chiffres du numéro de prêt comme un index dans le tableau de bits. Sauvagement rapide, et au bout de 8 mois, a prouvé que le système mainframe nous avons été l'obtention de données est en fait mal. La simplicité de bits tableaux fait confiance dans leur exactitude très élevée - par opposition à une approche de la recherche par exemple.
bool
. Peut-être même 4 octets pour C89 configurations qui utilisentint
à mettre en œuvrebool
Utiliser l'un des opérateurs tels que définis ici.
À définir un peu, utilisé
int x = x | 0x?;
où?
est la position du bit dans la forme binaire.0x
est le préfixe pour un littéral en hexadécimal, binaire pas.Voici quelques macros que j'utilise:
Variable utilisée
valeur des Données
pos - position de la partie qui nous intéresse, à définir, supprimer ou à bascule.
Définir un peu:
Clair un peu:
Bascule un peu:
À l'adresse d'une codification commune piège lors d'une tentative pour former le masque:
1
n'est pas toujours assez largeQuels sont les problèmes qui se produisent lorsque
number
est plus large que ce que1
?x
peut-être trop grand pour la maj1 << x
conduisant à comportement indéfini (UB). Même six
n'est pas trop grande,~
ne peut pas les retourner assez de plus-importante-bits.Pour assurer 1 est assez large:
Code pourrait utiliser
1ull
ou de manière affectée(uintmax_t)1
et laisser le compilateur d'optimiser.Ou de la fonte qui fait de codage/examen/problèmes d'entretien, de maintien de la distribution correcte et à jour.
Ou doucement promouvoir la
1
en forçant une opération mathématique qui soit au moins aussi large que le type denumber
.Comme avec la plupart des bits de manipulations, il est préférable de travailler avec unsigned types plutôt que signé ceux
number |= (type_of_number)1 << x;
ninumber |= (number*0 + 1) << x;
approprié pour définir le bit de signe d'un type signé... Comme une question de fait, ce n'estnumber |= (1ull << x);
. Est-il un portable de façon à le faire par la poste?C++11 basées sur des modèles de version (mettez-les dans un en-tête):
;
après votre définition d'une fonction?)(variable & bits == bits)
?((variable & bits) == bits)
std::bitset
en c++11Comment obtenir un peu?
nth
peu de num décalage à droitenum
,n
fois. Puis effectuer au niveau du bit ET&
avec 1.Comment ça marche?
Comment définir un peu?
n
fois. Puis effectuer au niveau du bit OU|
opération avecnum
.Comment ça marche?
Comment effacer un peu?
n
fois, c'est à dire1 << n
.~ (1 << n)
.&
opération avec le résultat ci-dessus etnum
. Les trois étapes ci-dessus peut être écrit commenum & (~ (1 << n))
;Comment ça marche?
Comment basculer un peu?
Pour alterner un peu, nous utilisons XOR au niveau du bit
^
de l'opérateur. XOR au niveau du bit opérateur prend la valeur 1 si le bit correspondant de deux opérandes sont différents, sinon renvoie 0.Ce qui signifie pour alterner un peu, nous avons besoin pour effectuer l'opération XOR avec le peu que vous souhaitez activer et 1.
Comment ça marche?
0 ^ 1 => 1
.1 ^ 1 => 0
.Recommandé la lecture - Opérateur au niveau du bit exercices
Essayez l'une de ces fonctions dans le langage C pour changer de n bits:
Ou
Ou
value << n
peut provoquer un comportement indéterminé