C / C ++ vérifie si un bit est défini dans, c.-à-d. Variable int

101
int temp = 0x5E; // in binary 0b1011110.

Existe-t-il un moyen de vérifier si le bit 3 de temp est 1 ou 0 sans décalage de bit ni masquage.

Je veux juste savoir s'il existe une fonction intégrée pour cela, ou suis-je obligé d'en écrire une moi-même.

Milan
la source

Réponses:

158

En C, si vous souhaitez masquer la manipulation de bits, vous pouvez écrire une macro:

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

et utilisez-le de cette façon pour vérifier le n ième bit à partir de l'extrémité droite:

CHECK_BIT(temp, n - 1)

En C ++, vous pouvez utiliser std :: bitset .

mouviciel
la source
3
Au cas où vous auriez besoin d'une valeur de vérité simple, elle devrait être !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu
10
@Eduard: en C, tout != 0est vrai, alors pourquoi s'embêter? 1est exactement aussi vrai que 0.1415!
Christoph
1
Et si vous utilisez C ++, vous pouvez (devriez) écrire un modèle au lieu d'une macro. :)
jalf
2
En C c'est très bien. Mais ce genre de macros en C ++. C'est horrible et si ouvert aux abus. Utilisez std :: bitset
Martin York
5
Ugh std::bitset, vraiment? Bien sûr, plutôt que de faire un tout petit peu de travail (et potentiellement de très bons modèles) pour vérifier un seul bit, utilisez un conteneur gonflé qui stocke (sur mon implémentation) chaque 'bit' dans un autre inutilisé unsigned long. Quelle perte d'espace!
underscore_d
86

Vérifiez si le bit N (à partir de 0) est activé:

temp & (1 << N)

Il n'y a pas de fonction intégrée pour cela.

Joao da Silva
la source
16
+1 pour avoir mentionné qu'il commence à 0 car je soupçonne que l'OP pensait basé sur 1 et la réponse acceptée lui causera des ennuis. :)
Jim Buck
Hm. Pourquoi est-ce à partir de 0? Qu'est-ce qu'on obtient quand 1 << 0?? Désolé, confus.
Danijel
6
OK, compris. Nous partons de la 0e possibilité, qui est de 1<<01 sans décalage (décalage 0), ce qui est1<<0 == 1
Danijel
27

J'utiliserais juste un std :: bitset si c'est C ++. Facile. Simple. Aucune chance pour des erreurs stupides.

typedef std::bitset<sizeof(int)> IntBits;
bool is_set = IntBits(value).test(position);

ou que diriez-vous de cette sottise

template<unsigned int Exp>
struct pow_2 {
    static const unsigned int value = 2 * pow_2<Exp-1>::value;
};

template<>
struct pow_2<0> {
    static const unsigned int value = 1;
};

template<unsigned int Pos>
bool is_bit_set(unsigned int value)
{
    return (value & pow_2<Pos>::value) != 0;
} 

bool result = is_bit_set<2>(value);
user21714
la source
4
@ user21714 Je suppose que vous vouliez dire std :: bitset <8 * sizeof (int)>
iNFINITEi
ou std :: numeric_limits <int> :: digits
Léo Lam
@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>pour être encore plus correct
Xeverous
14

Ce que fait la réponse choisie est en fait faux. La fonction ci-dessous renverra la position du bit ou 0 selon que le bit est réellement activé. Ce n'est pas ce que demandait l'affiche.

#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))

Voici ce que l'affiche recherchait à l'origine. La fonction ci-dessous renverra un 1 ou un 0 si le bit est activé et non la position.

#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
shocker92
la source
1
Il a fallu un certain temps avant que je comprenne ce que vous voulez dire. Plus exact: la première fonction renvoie 2 à la puissance de la position du bit si le bit est à 1, 0 sinon.
lukasl1991
1
C'est le problème exact que je viens de rencontrer en l'utilisant comme bool has_feature = CHECK_BIT(register, 25);Bon à savoir que je pourrais le faire sans la double négation.
Jimmio92
13

Ouais, je sais que je ne suis pas « avoir » le faire de cette façon. Mais j'écris habituellement:

    /* Return type (8/16/32/64 int size) is specified by argument size. */
template<class TYPE> inline TYPE BIT(const TYPE & x)
{ return TYPE(1) << x; }

template<class TYPE> inline bool IsBitSet(const TYPE & x, const TYPE & y)
{ return 0 != (x & y); }

Par exemple:

IsBitSet( foo, BIT(3) | BIT(6) );  // Checks if Bit 3 OR 6 is set.

Entre autres, cette approche:

  • Accepte les entiers 8/16/32/64 bits.
  • Détecte les appels IsBitSet (int32, int64) à mon insu et sans mon consentement.
  • Modèle intégré, donc aucune fonction appelant la surcharge.
  • const & références, donc rien n'a besoin d'être dupliqué / copié. Et nous sommes assurés que le compilateur détectera toute faute de frappe qui tente de modifier les arguments.
  • 0! = Rend le code plus clair et plus évident. Le point principal de l'écriture de code est toujours de communiquer clairement et efficacement avec d'autres programmeurs, y compris ceux de moindre compétence.
  • Bien que cela ne s'applique pas à ce cas particulier ... En général, les fonctions basées sur des modèles évitent le problème de l'évaluation des arguments plusieurs fois. Un problème connu avec certaines macros #define.
    Par exemple: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);
Monsieur Ree
la source
11

Selon cette description des champs de bits , il existe une méthode pour définir et accéder directement aux champs. L'exemple de cette entrée va:

struct preferences {
    unsigned int likes_ice_cream : 1;
    unsigned int plays_golf : 1;
    unsigned int watches_tv : 1;
    unsigned int reads_books : 1;
}; 

struct preferences fred;

fred.likes_ice_cream = 1;
fred.plays_golf = 1;
fred.watches_tv = 1;
fred.reads_books = 0;

if (fred.likes_ice_cream == 1)
    /* ... */

En outre, il y a un avertissement là-bas:

Cependant, les membres bit dans les structures présentent des inconvénients pratiques. Premièrement, l'ordre des bits en mémoire dépend de l'architecture et les règles de remplissage de la mémoire varient d'un compilateur à l'autre. En outre, de nombreux compilateurs populaires génèrent du code inefficace pour la lecture et l'écriture de membres de bits, et il existe des problèmes de sécurité des threads potentiellement graves liés aux champs de bits (en particulier sur les systèmes multiprocesseurs) en raison du fait que la plupart des machines ne peuvent pas manipuler des ensembles arbitraires de bits en mémoire, mais doit à la place charger et stocker des mots entiers.

gimel
la source
5

Utilisez std :: bitset

#include <bitset>
#include <iostream>

int main()
{
    int temp = 0x5E;
    std::bitset<sizeof(int)*CHAR_BITS>   bits(temp);

    // 0 -> bit 1
    // 2 -> bit 3
    std::cout << bits[2] << std::endl;
}
Martin York
la source
1
Quelques choses à mentionner ici - bits [3] vous donneront le 4ème bit - en comptant du LSB au MSB. Pour le dire vaguement, cela vous donnera le 4 bits comptant de droite à gauche. De plus, sizeof (int) donne le nombre de caractères dans un int, il faudrait donc std :: bitset <sizeof (int) * CHAR_BITS> bits (temp), et bits [sizeof (int) * CHAR_BITS - 3] pour tester le 3ème comptage de bits de MSB à LSB, ce qui est probablement l'intention.
plastic chris
2
Oui, mais je pense que le questionneur (et les personnes issues des recherches Google) n'ont peut-être pas cette compétence, et votre réponse pourrait les induire en erreur.
plastic chris
Cette réponse est terrible. Il devrait être supprimé.
Adam Burry
La valeur tempn'a- t-elle pas besoin d'être reflétée pour la rendre "big-endian"?
jww
4

Il y a, à savoir l' instruction intrinsèque _bittest .

Dave Van den Eynde
la source
3
Le lien indique «Microsoft Specific». Utilisez-le uniquement si vous n'avez pas besoin de votre code pour être portable.
mouviciel
Le lien indique «Microsoft Specific», mais il s'agit d'une reprise intrinsèque du compilateur Intel C ++, et il en résulte une instruction BT, vous pouvez donc également le faire avec l'assembleur en ligne. Bien sûr, cela ne le rend pas plus portable.
Dave Van den Eynde
1
Il est également spécifique à l'architecture x86. Donc non, certainement pas portable.
jalf
Je suis sûr que d'autres architectures ont des options similaires.
Dave Van den Eynde
L'intérêt même des intrinsèques est qu'ils tirent parti du matériel s'il existe et utilisent un logiciel de remplacement si le matériel ne le gère pas.
Eclipse
4

J'utilise ceci:

#define CHECK_BIT(var,pos) ( (((var) & (pos)) > 0 ) ? (1) : (0) )

où "pos" est défini comme 2 ^ n (ig 1,2,4,8,16,32 ...)

Renvoie: 1 si vrai 0 si faux

AnthropicDream
la source
2
Je pense que c'est la seule bonne réponse pour C et C ++. C'est le seul qui respecte l' exigence "... sans décalage et masquage de bits" . Vous devriez probablement déclarer explicitement à utiliser 4 = 2^(3-1)pour la position de bit 3 car cela faisait partie de la question.
jww
3

J'essayais de lire un entier 32 bits qui définissait les indicateurs d'un objet dans les PDF et cela ne fonctionnait pas pour moi

ce qui a corrigé c'était de changer la définition:

#define CHECK_BIT(var,pos) ((var & (1 << pos)) == (1 << pos))

l'opérande & renvoie un entier avec les indicateurs qui ont tous les deux en 1, et il n'a pas été converti correctement en booléen, cela a fait l'affaire

Ismael
la source
!= 0ferait de même. Je ne sais pas en quoi les instructions machine générées peuvent différer.
Adam Burry
2

Vous pouvez "simuler" le décalage et le masquage: if ((0x5e / (2 * 2 * 2))% 2) ...

Léonidas
la source
Nous pourrions trier une liste en la mélangeant au hasard et en testant pour voir si elle est maintenant "triée". Par exemple: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Mais nous ne ...
Mr.Ree
Cette solution est extrêmement gourmande en ressources et peu intuitive. divs, muls et mods sont les trois fonctions les plus coûteuses. par des tests de comparaison, les ands et les quarts de travail sont parmi les moins chers - certains des rares que vous pourriez réellement faire en moins de 5 cycles.
jheriko
Cela pourrait être (et ne l'est pas, car les processeurs modernes détestent les bits et les sauts). L'OP a initialement demandé explicitement une solution «sans décalage de bits ni masquage». Alors continuez et donnez plus de points négatifs pour une réponse correspondante mais lente. Je ne supprimerai pas le message simplement parce que le PO a changé d'avis.
Leonidas
Cela semble délicat. Ne votons pas contre cette réponse. Parfois, il est bon d'explorer d'autres points de vue.
Viet du
2

Pour la solution spécifique x86 de bas niveau, utilisez l' opcode x86 TEST .

Votre compilateur devrait cependant transformer _bittest en ceci ...

jheriko
la source
Je préférerais BT à TEST car BT répond mieux à la tâche.
u_Ltd.
1

Pourquoi ne pas utiliser quelque chose d'aussi simple que cela?

uint8_t status = 255;
cout << "binary: ";

for (int i=((sizeof(status)*8)-1); i>-1; i--)
{
  if ((status & (1 << i)))
  {
    cout << "1";
  } 
  else
  {
    cout << "0";
  }
}

SORTIE: binaire: 11111111

zeilja
la source
si d' autre peut se faire facilement avec un ternaire: std::cout << (((status & (1 << i)) ? '1' : '0');. Vous devriez utiliser la CHAR_BITconstante de <climits>au lieu de coder en dur 8 bits, mais dans ce cas, vous savez que le résultat sera de toute façon 8 puisque vous utilisez unuint8_t
Ryan Haining
0

si vous voulez juste un vrai moyen codé en dur:

 #define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )

notez cette hw dépendant et suppose que cet ordre de bits 7654 3210 et var est de 8 bits.

#include "stdafx.h"
#define IS_BIT3_SET(var) ( ((var) & 0x04) == 0x04 )
int _tmain(int argc, _TCHAR* argv[])
{
    int temp =0x5E;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x00;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0x04;
    printf(" %d \n", IS_BIT3_SET(temp));
    temp = 0xfb;
    printf(" %d \n", IS_BIT3_SET(temp));
    scanf("waitng %d",&temp);

    return 0;
}

Résulte en:

1 0 1 0

Simon
la source
1
L'opération & est effectuée sur des valeurs non sur la représentation interne.
Remo.D
Salut Remo.D - Je ne suis pas sûr de comprendre votre commentaire? J'ai inclus du code «c» qui fonctionne très bien.
simon
Son point est que cela ne dépend pas du matériel - IS_BIT3_SET testera toujours le 4ème bit le moins significatif
Eclipse
0

Bien qu'il soit assez tard pour répondre maintenant, il existe un moyen simple de trouver si le Nième bit est défini ou non, en utilisant simplement les opérateurs mathématiques POWER et MODULUS.

Disons que nous voulons savoir si «temp» a un Nième bit défini ou non. L'expression booléenne suivante donnera vrai si le bit est défini, 0 sinon.

  • (temp MODULE 2 ^ N + 1> = 2 ^ N)

Prenons l'exemple suivant:

  • int temp = 0x5E; // en binaire 0b1011110 // BIT 0 est LSB

Si je veux savoir si le 3ème bit est activé ou non, j'obtiens

  • (94 MODULE 16) = 14> 2 ^ 3

L'expression renvoie donc vrai, indiquant que le 3ème bit est défini.

Ouroboros
la source
0

Une approche consistera à vérifier dans la condition suivante:

if ( (mask >> bit ) & 1)

Un programme d'explication sera:

#include <stdio.h>

unsigned int bitCheck(unsigned int mask, int pin);

int main(void){
   unsigned int mask = 6;  // 6 = 0110
   int pin0 = 0;
   int pin1 = 1;
   int pin2 = 2;
   int pin3 = 3;
   unsigned int bit0= bitCheck( mask, pin0);
   unsigned int bit1= bitCheck( mask, pin1);
   unsigned int bit2= bitCheck( mask, pin2);
   unsigned int bit3= bitCheck( mask, pin3);

   printf("Mask = %d ==>>  0110\n", mask);

   if ( bit0 == 1 ){
      printf("Pin %d is Set\n", pin0);
   }else{
      printf("Pin %d is not Set\n", pin0);
   }

    if ( bit1 == 1 ){
      printf("Pin %d is Set\n", pin1);
   }else{
      printf("Pin %d is not Set\n", pin1);
   }

   if ( bit2 == 1 ){
      printf("Pin %d is Set\n", pin2);
   }else{
      printf("Pin %d is not Set\n", pin2);
   }

   if ( bit3 == 1 ){
      printf("Pin %d is Set\n", pin3);
   }else{
      printf("Pin %d is not Set\n", pin3);
   }
}

unsigned int bitCheck(unsigned int mask, int bit){
   if ( (mask >> bit ) & 1){
      return 1;
   }else{
      return 0;
   }
}

Production:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set
Michi
la source
0
#define CHECK_BIT(var,pos) ((var>>pos) & 1)

pos - Position de bit commençant à 0.

renvoie 0 ou 1.

Artūrs Laizāns
la source
-1

Je fais ceci:

LATGbits.LATG0 = ((m & 0x8)> 0); // pour vérifier si le bit-2 de m est 1

mathématicien
la source
-2

le moyen le plus rapide semble être une table de recherche pour les masques

oldUser
la source