从字节获取特定位

问题描述 投票:0回答:1

我有一个字节,特别是来自字节数组的一个字节,它通过从另一个设备发送的UDP进入。该字节存储器件中8个继电器的开/关状态。

如何获取所述字节中特定位的值?理想情况下,扩展方法看起来最优雅,返回bool对我来说最有意义。

public static bool GetBit(this byte b, int bitNumber)
{
    //black magic goes here
}
c# arrays byte bit
1个回答
154
投票

简单。使用按位AND将您的数字与值2 ^ bitNumber进行比较,这可以通过位移来便宜地计算。

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

编辑:添加更多细节,因为有很多类似的答案,没有解释:

按位AND使用AND连接逐位比较每个数字,以产生一个数字,该数字是位置的组合,其中该位置的第一位和第二位都被设置。这是“半字节”中AND逻辑的逻辑矩阵,它显示了按位AND的操作:

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

在您的情况下,我们将您传递的数字与仅包含您要查找的位的数字进行比较。假设您正在寻找第四位:

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

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

比特移位,产生我们想要比较的数字,正如它听起来的那样:取数字,表示为一组比特,并将这些比特向左或向右移动一定数量的位置。因为这些是二进制数,因此每个位是比其右边的位更大的二次幂,向左移位相当于每个移位的位数加倍一次,相当于将数字乘以2 ^ x的。在您的示例中,查找第四位,我们执行:

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

现在你知道它是如何完成的,在低层发生了什么,以及它为什么会起作用。


1
投票
[Flags]
enum Relays : byte
{
    relay0 = 1 << 0,
    relay1 = 1 << 1,
    relay2 = 1 << 2,
    relay3 = 1 << 3,
    relay4 = 1 << 4,
    relay5 = 1 << 5,
    relay6 = 1 << 6,
    relay7 = 1 << 7
}

public static bool GetRelay(byte b, Relays relay)
{
    return (Relays)b.HasFlag(relay);
}

51
投票

虽然阅读和理解Josh的答案是好的,但是你可能会更乐意使用Microsoft为此目的提供的类:System.Collections.BitArray它可以在所有版本的.NET Framework中使用。


36
投票

这个

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

应该这样做,我想。


9
投票

这样做的另一种方式:)

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

6
投票

使用BitArray类并将扩展方法作为OP建议:

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

4
投票

试试这个:

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

4
投票

这比0.1毫秒更快。

return (b >> bitNumber) & 1;

3
投票

该方法是使用另一个字节以及按位AND来屏蔽目标位。

我在这里的类中使用了约定,其中“0”是最重要的位,“7”是最小的。

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

3
投票

请尝试下面的代码。与其他帖子的不同之处在于您可以使用掩码(field)设置/获取多个位。例如,第4位的掩码可以是1 << 3或0x10。

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

**示例**

        bool is_ok = 0x01AF.GetBits(0x10); //false
        int res = 0x01AF.SetBits(0x10, true);
        is_ok = res.GetBits(0x10);  // true
© www.soinside.com 2019 - 2024. All rights reserved.