2011-01-31 11 views
74

Tengo un byte, específicamente un byte de un conjunto de bytes que entró vía UDP enviado desde otro dispositivo. Este byte almacena el estado de encendido/apagado de 8 relés en el dispositivo.Obtiene un bit específico del byte

¿Cómo obtengo el valor de un bit específico en dicho byte? Idealmente, un método de extensión sería el más elegante y devolver un bool tendría más sentido para mí.

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

Respuesta

136

Fácil. Use un Y a nivel de bits para comparar su número con el valor 2^bitNumber, que se puede calcular de manera económica mediante el cambio de bit.

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

EDIT: Para añadir un poco más de detalle, porque hay una gran cantidad de respuestas similares con ninguna explicación:

Un bit a bit y lo compara cada número, bit por bit, utilizando un AND unirse para producir un número que es la combinación de bits donde se establecieron tanto el primer bit como el segundo bit en ese lugar. Aquí está la matriz lógica de la lógica AND en un "mordisco" que muestra el funcionamiento de una función Y:

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

En su caso, se compara el número que ha pasado con un número que tiene solamente el bit que desea buscar para el set Digamos que usted está buscando el cuarto bit:

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

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

de desplazamiento de bits, para producir el número que queremos comparar en contra, es exactamente lo que parece: tomar el número, representado como un conjunto de bits, y desplaza esos bits hacia la izquierda o hacia la derecha en un cierto número de lugares. Debido a que estos son números binarios y cada bit es una potencia mayor de dos que la de su derecha, el cambio de bit a la izquierda equivale a duplicar el número una vez por cada lugar que se desplaza, lo que equivale a multiplicar el número por 2^x. En su ejemplo, buscando el cuarto bit, realizamos:

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

Ahora sabes cómo se hace, lo que está pasando en el nivel bajo, y por qué funciona.

+7

Debido a que faltan llaves (precedencia del operador) este código no se compila, debe ser 'var bit = (b & (1 << bitNumber-1))! = 0'; – bitbonk

3

probar esto:

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

Este

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

debe hacerlo, creo.

43

Si bien es bueno leer y comprender la respuesta de Josh, probablemente sea más feliz usando la clase que Microsoft proporcionó para este fin: System.Collections.BitArray Está disponible en todas las versiones de .NET Framework.

+6

+1 para la solución incorporada. :) – Sapph

+0

Esto es fabuloso, pero creo que la solución de Josh es mucho más rápida y más eficiente. –

+0

@ user2332868: el compilador JIT reconoce especialmente las llamadas a ciertas funciones de la biblioteca y genera un código eficiente, pero no tengo idea de si estas funciones en particular reciben el amor. –

3

El método consiste en utilizar otro byte junto con un Y bit para enmascarar el bit de destino.

Usé la convención de mis clases aquí donde "0" es el bit más significativo y "7" es el menos.

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

otra forma de hacerlo :)

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

Esto no funcionará: byte b = 1; return ((b >> 1) & 1)! = 0 (es igual a 0) –

+0

Hmmm ... No te entiendo. Si byte b = 1, el bit en la posición 0 es 1, dado por (b >> 0) & 1, y el bit en cualquier posición mayor o igual que 1 es 0, dado por (b >> n) & 1 donde n> = 1 así como – PierrOz

+0

No creo que eso lo haga para nada @DavideAndrea, el comentario publicado por Rafael asume que el bit de la derecha es el bit 1, pero el código de PierrOz es para cuando el bit de la derecha es el bit 0. Si b fue 2, entonces '((2 >> 1) & 1)' es '1' y' ((2 >> 0) & 1) 'es' 0' porque 2 es '00000010' –

2

Prueba el código de abajo. La diferencia con otras publicaciones es que puedes establecer/obtener múltiples bits usando una máscara (field). La máscara para el 4to bit puede ser 1 < < 3, o 0x10, por ejemplo.

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

** Ejemplo **

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

Usando BitArray clase y haciendo un método de extensión como sugiere 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, por favor no cree y deseche un BitArray para cada prueba de bit. –

+0

@BenVoigt, es un método de extensión en un byte por solicitud OP. ¿Dónde recomiendas almacenar la instancia de BitArray? –

+2

Usted rechaza la solicitud y dice, no lo llame como un método en el byte, llámelo en el BitArray. Tal vez la variable byte puede desaparecer por completo. –

2

Esto es funciona más rápido que 0,1 milisegundos.

Cuestiones relacionadas