2011-01-31 14 views
74

Ho un byte, in particolare un byte da un array di byte che è arrivato tramite UDP inviato da un altro dispositivo. Questo byte memorizza lo stato on/off di 8 relè nel dispositivo.Ottieni un bit specifico dal byte

Come si ottiene il valore di un bit specifico in detto byte? Idealmente, un metodo di estensione apparirebbe il più elegante e restituire un bool avrebbe più senso per me.

public static bool GetBit(this byte b, int bitNumber) 
{ 
    //black magic goes here 
} 

risposta

136

Facile. Utilizza un AND bit a bit per confrontare il tuo numero con il valore 2^bitNumber, che può essere calcolato a buon mercato con lo spostamento dei bit.

//your black magic 
var bit = (b & (1 << bitNumber-1)) != 0; 

EDIT: Per aggiungere un po 'più in dettaglio perché ci sono un sacco di risposte simili senza alcuna spiegazione:

Un bit a bit e mette a confronto ogni numero, bit per bit, utilizzando una e si uniscono per produrre un numero che è la combinazione di bit in cui sono stati impostati sia il primo bit che il secondo bit in quel punto. Ecco la matrice logica della logica AND in un "bocconcino" che mostra il funzionamento di un AND bit per bit:

0101 
& 0011 
    ---- 
    0001 //Only the last bit is set, because only the last bit of both summands were set 

Nel tuo caso, si confronta il numero è stato superato con un numero che ha solo il bit che si desidera cercare per set. Diciamo che stai cercando il quarto bit:

11010010 
& 00001000 
    -------- 
    00000000 //== 0, so the bit is not set 

    11011010 
& 00001000 
    -------- 
    00001000 //!= 0, so the bit is set 

Bit-shifting, per produrre il numero che vogliamo confrontare con, è esattamente quello che sembra: prendere il numero, rappresentato come un insieme di bit, e sposta quei bit a sinistra oa destra di un certo numero di punti. Poiché si tratta di numeri binari e quindi ogni bit è un potere-di-due maggiore di quello alla sua destra, lo spostamento dei bit verso sinistra equivale a raddoppiare il numero una volta per ogni punto spostato, equivalente a moltiplicare il numero per 2^x. Nel tuo esempio, alla ricerca del quarto bit, eseguiamo:

 1 (2^0) << (4-1) ==  8 (2^3) 
00000001  << (4-1) == 00001000 

Ora si sa come è fatto, quello che sta succedendo a livello basso, e perché funziona.

+7

A causa di parentesi mancanti (precedenza operatore) questo codice non viene compilato, deve essere 'var bit = (b & (1 << bitNumber-1))! = 0'; – bitbonk

3

provare questo:

return (b & (1 << bitNumber))>0; 
31

Questo

public static bool GetBit(this byte b, int bitNumber) { 
    return (b & (1 << bitNumber)) != 0; 
} 

dovrebbe farlo, penso.

43

Mentre è buona norma leggere e comprendere la risposta di Josh, probabilmente sarai più contento di utilizzare la classe Microsoft fornita a questo scopo: System.Collections.BitArray È disponibile in tutte le versioni di .NET Framework.

+6

+1 per la soluzione integrata. :) – Sapph

+0

Questo è favoloso ma credo che la soluzione di Josh sia molto più veloce ed efficiente. –

+0

@ user2332868: il compilatore JIT riconosce in particolare le chiamate a determinate funzioni di libreria e genera codice efficiente, ma non ho idea se queste particolari funzioni ottengano l'amore. –

3

Il metodo consiste nell'utilizzare un altro byte insieme a un AND per bit per mascherare il bit di destinazione.

Ho usato la convenzione dalle mie classi qui dove "0" è il bit più significativo e "7" è il minimo.

public static class ByteExtensions 
{ 
    // Assume 0 is the MSB andd 7 is the LSB. 
    public static bool GetBit(this byte byt, int index) 
    { 
     if (index < 0 || index > 7) 
      throw new ArgumentOutOfRangeException(); 

     int shift = 7 - index; 

     // Get a single bit in the proper position. 
     byte bitMask = (byte)(1 << shift); 

     // Mask out the appropriate bit. 
     byte masked = (byte)(byt & bitMask); 

     // If masked != 0, then the masked out bit is 1. 
     // Otherwise, masked will be 0. 
     return masked != 0; 
    } 
} 
8

un altro modo di farlo :)

return ((b >> bitNumber) & 1) != 0; 
+1

Questo non funzionerà: byte b = 1; return ((b >> 1) & 1)! = 0 (è uguale a 0) –

+0

Hmmm ... Non ti capisco. Se byte b = 1, bit in posizione 0 è 1, dato da (b >> 0) & 1, e bit in qualsiasi posizione maggiore o uguale a 1 è 0, dato da (b >> n) e 1 dove n> = 1 pure – PierrOz

+0

Non credo che lo faccia per niente @DavideAndrea, il commento postato da Rafael presuppone che il bit più a destra sia il bit 1, ma il codice di PierrOz è per quando il bit più a destra è il bit 0. Se b era 2, allora '((2 >> 1) & 1)' è '1' e' ((2 >> 0) & 1) 'è' 0' perché 2 è '00000010' –

2

provare il codice qui sotto. La differenza con altri post è che puoi impostare/ottenere più bit usando una maschera (field). La maschera per il 4 ° bit può essere 1 < 3 o 0x10, ad esempio.

public int SetBits(this int target, int field, bool value) 
    { 
     if (value) //set value 
     { 
      return target | field; 
     } 
     else //clear value 
     { 
      return target & (~field); 
     } 
    } 

    public bool GetBits(this int target, int field) 
    { 
     return (target & field) > 0; 
    } 

** ** Esempio

 bool is_ok = 0x01AF.GetBits(0x10); //false 
     int res = 0x01AF.SetBits(0x10, true); 
     is_ok = res.GetBits(0x10); // true 
7

Uso BitArray classe e facendo un metodo di estensione come suggerisce OP:

public static bool GetBit(this byte b, int bitNumber) 
{ 
    System.Collections.BitArray ba = new BitArray(new byte[]{b}); 
    return ba.Get(bitNumber); 
} 
+8

No, per favore non creare e buttare via un BitArray per ogni bit test. –

+0

@BenVoigt, è un metodo di estensione su un byte per richiesta OP. Dove consiglieresti di archiviare l'istanza di BitArray? –

+2

Si respinge la richiesta e si dice, non chiamarla come un metodo sul byte, chiamarla su BitArray. Forse la variabile byte può andare completamente via. –

2

Questo funziona più veloce di 0,1 millisecondi.

return (b >> bitNumber) & 1;