Masque de bits en C
Quelle est la meilleure façon de construire un masque de bits en C avec m
bits précédée par k
unset bits, et suivie par n
unset bits:
00..0 11..1 00..0
k m n
Par exemple, k=1, m=4, n=3, le résultat serait le masque de bits:
01111000
- Pour obtenir des réponses à peu se tourner les hacks, comme cela, une très bonne source en ligne est Peu Tourner les Hacks.
- Habituellement, un masque de macros sont définies sur inclusif peu d'indices, quelque chose comme
#define BITS(p,q) ...
où p = m + n - 1 et q = n, p >= q - Hacker Plaisir est beaucoup plus complet (1.8 kilopages) et génial.
- Je ne comprends pas vraiment pourquoi vous avez besoin d'avoir
k
ici. C'est juste plus facile pour spécifier une plage de bits pour définir à l'aide dem
etn
seulement.
Vous devez vous connecter pour publier un commentaire.
~(~0 << m) << n
~(~0 << m)
est dans le paragraphe 2.9 "Opérateurs au niveau du Bit" de "Le Langage de Programmation C, deuxième édition" par Brian Kernighan et Dennis Ritchie. C'est aussi dans le paragraphe 7.5 "l'Efficacité de l'Espace" de "La Pratique de la Programmation" par Brian W. Kernighan et Rob Pike.integer overflow in preprocessor expression
.printf("%u\n", ((1 << 31) - 1) << 0);
génèrewarning: integer overflow in expression [-Woverflow]
. Je suis également d'accord avec Barry que le masque ne permet pas de définir le bit de poids fort d'un entier non signé. Est-il un moyen de contourner ce problème?~(~0u << m) << n
.Donc, vous demander de m bits de préfixe par k réinitialiser les bits et suivi de n réinitialiser les bits? On peut les ignorer, k, car il sera largement contraint par le choix de type entier.
J'aime bien les deux solutions. Voici un autre moyen qui me vient à l'esprit (sans doute pas mieux).
((~((unsigned int)0) << k) >> (k + n)) << n
EDIT:
Il y avait un bug dans ma version précédente (il était sans le unsigned int cast). Le problème était que
~0 >> n
ajoute 1 à l'avant et pas de 0.Et oui, cette approche présente un inconvénient majeur; il suppose que vous savez le nombre de bits de la valeur par défaut de type entier ou en d'autres termes, il suppose que vous savez vraiment k, tandis que les autres solutions sont indépendants de k. Cela rend ma version moins portable, ou au moins plus difficile de port. (Il utilise également les 3 quarts de travail, et plus et un bit à bit opérateur de négation, qui est de deux opérations.)
De sorte que vous feriez mieux d'utiliser l'un des autres exemples.
Voici une petite application de test, réalisé par Jonathan Leffler, de comparer et de vérifier la sortie des différentes solutions:
(Uniquement) Pour ceux qui sont intéressés de manière un peu plus efficace sur des systèmes x86 avec BMI2 de soutien (Intel Haswell ou plus récent, AMD Pelle ou une version plus récente):
La
bzhi
instruction des zéros de la haute bits en commençant par de bits spécifié position.Le
_bzhi_u32
intrinsèque compile à cette instruction. Le code de Test:De sortie:
Le fragment de code
_bzhi_u32(-1,m)<<n
compile trois instructionsQui est une instruction moins que les codes par @Jonathan Leffler
et @Darius Bacon.
Sur les processeurs Intel Haswell des processeurs ou plus récent, à la fois
bzhi
etshlx
ont un temps de latence de 1 cycle et unun débit de 2 par cycle. Sur AMD Ryzen ces deux instructions ont même un débit de 4 par cycle.
Tandis que la partie supérieure réponses sont simples et efficaces, ils ne réglez pas le MSB pour le cas où
n=0
etm=31
:~(~0 << 31) << 0
=0111 1111 1111 1111 1111 1111 1111 1111
((1 << 31)-1) << 0
=0111 1111 1111 1111 1111 1111 1111 1111
Ma suggestion pour un non signé de 32 bits du mot (ce qui est laid et dispose d'une succursale) ressemble à ceci:
Ce fait les bits dans la gamme
[m,n]
(intervalle fermé) donccreate_mask(0,0)
sera de retour un masque pour le premier bit (bit 0) etcreate_mask(4,6)
retourne un masque de bits 4 à 6 je.e... 00111 0000
.