C / C ++ controlla se un bit è impostato in, cioè int variabile


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

Esiste un modo per verificare se il bit 3 in temp è 1 o 0 senza cambio di bit e mascheramento.

Voglio solo sapere se c'è qualche funzione incorporata per questo, o sono costretto a scriverne una io stesso.

Risposte:


157

In C, se vuoi nascondere la manipolazione dei bit, puoi scrivere una macro:

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

e usalo in questo modo per controllare l' ennesimo bit dall'estremità destra:

CHECK_BIT(temp, n - 1)

In C ++, puoi usare std :: bitset .


3
Nel caso abbiate bisogno di un semplice valore di verità, dovrebbe essere !! ((var) & (1 << (pos))).
Eduard - Gabriel Munteanu

10
@Eduard: in C, != 0è tutto vero, quindi perché preoccuparsi? 1è esattamente vero come 0.1415!
Christoph

1
E nel caso in cui utilizzi C ++, potresti (dovresti) scrivere un modello invece di una macro. :)
jalf

2
In C questo va bene. Ma questo tipo di macro in C ++. È orribile e così suscettibile di abusi. Usa std :: bitset
Martin York

5
Uff std::bitset, davvero? Certo, piuttosto che fare un po 'di lavoro (e potenzialmente alcuni modelli davvero carini) per controllare un singolo bit, usa un contenitore gonfio che memorizza (nella mia implementazione) ogni "bit" in un altro inutilizzato unsigned long. Che spreco di spazio!
underscore_d

86

Verificare se il bit N (a partire da 0) è impostato:

temp & (1 << N)

Non esiste una funzione incorporata per questo.


16
+1 per aver menzionato che inizia da 0 poiché sospetto che l'OP pensasse a base 1 e la risposta accettata lo metterà nei guai. :)
Jim Buck,

Hm. Perché parte da 0? Cosa otteniamo quando 1 << 0?? Scusa, confuso.
Danijel

6
Ok capito. Partiamo dalla posizione 0, che è 1<<0, che è 1 senza alcun turno (turno 0), che è1<<0 == 1
Danijel

27

Vorrei solo usare uno std :: bitset se è C ++. Semplice. Straight-forward. Nessuna possibilità di errori stupidi.

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

o che ne dici di questa stupidità

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);

4
@ user21714 Immagino che tu intendessi std :: bitset <8 * sizeof (int)>
iNFINITEi

o std :: numeric_limits <int> :: cifre
Léo Lam

@iNFINITEi std::bitset<CHAR_BIT * sizeof(int)>per essere ancora più corretto
Xeverous

13

Sì, lo so che non "devo" farlo in questo modo. Ma di solito scrivo:

    /* 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); }

Per esempio:

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

Tra le altre cose, questo approccio:

  • Ospita numeri interi a 8/16/32/64 bit.
  • Rileva le chiamate IsBitSet (int32, int64) a mia insaputa e senza il mio consenso.
  • Modello inline, quindi nessuna funzione che chiama overhead.
  • const e riferimenti, quindi non è necessario duplicare / copiare nulla . E siamo garantiti che il compilatore rileverà qualsiasi errore di battitura che tenti di cambiare gli argomenti.
  • 0! = Rende il codice più chiaro e ovvio. Il punto principale per scrivere codice è sempre quello di comunicare in modo chiaro ed efficiente con altri programmatori, compresi quelli di minore abilità.
  • Sebbene non sia applicabile a questo caso particolare ... In generale, le funzioni basate su modelli evitano il problema di valutare gli argomenti più volte. Un problema noto con alcune macro #define.
    Ad esempio: #define ABS (X) (((X) <0)? - (X): (X))
          ABS (i ++);

13

Quello che sta facendo la risposta selezionata è effettivamente sbagliato. La funzione seguente restituirà la posizione del bit o 0 a seconda che il bit sia effettivamente abilitato. Questo non è ciò che chiedeva il poster.

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

Ecco cosa cercava originariamente il poster. La funzione seguente restituirà 1 o 0 se il bit è abilitato e non la posizione.

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

1
C'è voluto del tempo prima che capissi cosa intendi. Più esatto: la prima funzione restituisce 2 alla potenza della posizione del bit se il bit è impostato, 0 altrimenti.
lukasl1991

1
Questo è il problema esatto che ho appena riscontrato durante l'utilizzo come bool has_feature = CHECK_BIT(register, 25);Buono a sapersi che potrei farlo senza la doppia negazione.
Jimmio92

11

Secondo questa descrizione dei campi di bit , esiste un metodo per definire e accedere direttamente ai campi. L'esempio in questa voce 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)
    /* ... */

Inoltre, c'è un avviso lì:

Tuttavia, i membri di bit nelle strutture presentano svantaggi pratici. Innanzitutto, l'ordine dei bit in memoria dipende dall'architettura e le regole di riempimento della memoria variano da compilatore a compilatore. Inoltre, molti compilatori popolari generano codice inefficiente per la lettura e la scrittura di membri di bit, e ci sono problemi di sicurezza dei thread potenzialmente gravi relativi ai campi di bit (specialmente su sistemi multiprocessore) a causa del fatto che la maggior parte delle macchine non può manipolare set arbitrari di bit in memoria, ma deve invece caricare e memorizzare intere parole.



5

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

1
Un paio di cose degne di nota qui - i bit [3] ti daranno il quarto bit, contando da LSB a MSB. Per dirla in modo approssimativo, ti darà il 4 il bit che conta da destra a sinistra. Inoltre, sizeof (int) fornisce il numero di caratteri in un int, quindi dovrebbe essere std :: bitset <sizeof (int) * CHAR_BITS> bits (temp) e bits [sizeof (int) * CHAR_BITS - 3] per testare il terzo bit che conta da MSB a LSB, che è probabilmente l'intento.
plastica chris

2
Sì, ma penso che l'interrogante (e le persone provenienti dalle ricerche su Google) potrebbero non avere quell'abilità e la tua risposta potrebbe fuorviarli.
plastica chris,

Questa risposta è terribile. Dovrebbe essere cancellato.
Adam Burry

Non è tempnecessario riflettere il valore per renderlo "big-endian"?
jww

4

C'è, vale a dire l' istruzione intrinseca _bittest .


3
Il collegamento indica "Microsoft Specific". Usalo solo se non hai bisogno che il tuo codice sia portatile.
mouviciel

Il collegamento indica "Microsoft Specific", ma è un elemento intrinseco ripreso dal compilatore Intel C ++ e risulta in un'istruzione BT, quindi puoi farlo anche con l'assembler inline. Ovviamente questo non lo rende più portabile.
Dave Van den Eynde,

1
È anche specifico per l'architettura x86. Quindi no, decisamente non portatile.
jalf

Sono sicuro che altre architetture hanno opzioni simili.
Dave Van den Eynde,

Il vero punto di forza intrinseca è che sfruttano l'hardware, se esiste, e utilizzano un sostituto del software se l'hardware non lo gestisce.
Eclipse

4

Io uso questo:

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

dove "pos" è definito come 2 ^ n (ig 1,2,4,8,16,32 ...)

Restituisce: 1 se vero 0 se falso


2
Penso che questa sia l'unica risposta corretta sia per C che per C ++. È l'unico che rispetta il requisito "... senza bit shifting e mascheramento" . Probabilmente dovresti dichiarare esplicitamente di usare 4 = 2^(3-1)per la posizione del bit 3 poiché faceva parte della domanda.
jww

3

stavo cercando di leggere un numero intero a 32 bit che definiva i flag per un oggetto nei PDF e questo non funzionava per me

ciò che ha risolto stava cambiando la definizione:

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

l'operando & restituisce un numero intero con i flag che hanno entrambi in 1, e non è stato trasmesso correttamente in booleano, questo ha funzionato


!= 0farebbe lo stesso. Non so come potrebbero differire le istruzioni della macchina generate.
Adam Burry

2

Puoi "simulare" lo spostamento e il mascheramento: if ((0x5e / (2 * 2 * 2))% 2) ...


Potremmo ordinare un elenco mescolandolo casualmente e testando per vedere se ora è "ordinato". Ad esempio: while (/ * NOT * /! IsSorted ()) {RandomlyShuffle (); } Ma non ...
Mr. Ree

Questa soluzione è estremamente dispendiosa in termini di risorse e poco intuitiva. divs, muls e mods sono le tre funzioni più costose. in base ai test di confronto, gli and e i turni sono tra i più economici, alcuni dei pochi che potresti effettivamente completare in meno di 5 cicli.
jheriko,

Potrebbe essere (e non lo è, perché i processori moderni detestano bit e salti). Inizialmente, l'OP chiedeva esplicitamente una soluzione "senza spostamento di bit e mascheramento". Quindi vai avanti e dai più punti negativi per una risposta corrispondente ma lenta. Non cancellerò il post solo perché l'OP ha cambiato idea.
Leonidas,

Sembra complicato. Non votiamo per difetto questa risposta. A volte è utile esplorare altri punti di vista.
Viet

2

Per la soluzione specifica x86 di basso livello, utilizzare il codice operativo x86 TEST .

Il tuo compilatore dovrebbe trasformare _bittest in questo però ...


Preferirei BT rispetto a TEST poiché BT si adatta meglio al compito.
u_Ltd.

1

Perché non usare qualcosa di così semplice come questo?

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

USCITA: binario: 11111111


se il resto può essere fatto facilmente con un ternario: std::cout << (((status & (1 << i)) ? '1' : '0');. Dovresti usare la CHAR_BITcostante da <climits>invece di codificare 8 bit, anche se in questo caso sai che il risultato sarà comunque 8 poiché stai usando unuint8_t
Ryan Haining

0

se vuoi solo un vero modo hard coded:

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

nota questo hw dipendente e assume che questo ordine di bit 7654 3210 e var sia 8 bit.

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

Risultati in:

1 0 1 0


1
L'operazione & viene eseguita sui valori non sulla rappresentazione interna.
Rimborso,

Ciao Remo.D - Non sei sicuro di aver capito il tuo commento? Ho incluso del codice "c" che funziona perfettamente.
simon

Il punto è che non dipende dall'hardware - IS_BIT3_SET testerà sempre il quarto bit meno significativo
Eclipse

0

Anche se ora è abbastanza tardi per rispondere, c'è un modo semplice per scoprire se l'ennesimo bit è impostato o meno, semplicemente usando gli operatori matematici POWER e MODULUS.

Supponiamo di voler sapere se 'temp' ha l'ennesimo bit impostato o meno. La seguente espressione booleana restituirà true se il bit è impostato, 0 in caso contrario.

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

Considera il seguente esempio:

  • int temp = 0x5E; // in binario 0b1011110 // BIT 0 è LSB

Se voglio sapere se il terzo bit è impostato o meno, ottengo

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

Quindi l'espressione restituisce vero, indicando che il terzo bit è impostato.


0

Un approccio verificherà la seguente condizione:

if ( (mask >> bit ) & 1)

Un programma di spiegazione sarà:

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

Produzione:

Mask = 6 ==>>  0110
Pin 0 is not Set
Pin 1 is Set
Pin 2 is Set
Pin 3 is not Set

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

pos - Posizione del bit a partire da 0.

restituisce 0 o 1.


-1

Faccio questo:

LATGbits.LATG0 = ((m & 0x8)> 0); // per verificare se il bit-2 di m è 1


-2

il modo più veloce sembra essere una tabella di ricerca per le maschere

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.