如何从一个字节中分离出每个比特?

12

我对C#(以及C语言)非常陌生。 我从外部来源获取一个表示IO设备端口上8个输入引脚状态的字节值,因此我得到一个0-255的值,代表端口上存在的二进制模式。

我该如何提取单独的位并将它们设置为布尔变量?例如:

if (inputBuffer[1] == 1)
{
     IO.Input0 = true;
     IO.Input1 = false;
     IO.Input2 = false;
     IO.Input3 = false;
     IO.Input4 = false;
     IO.Input5 = false;
     IO.Input6 = false;
     IO.Input7 = false;
}    

我可能在过度解释我想要实现的内容,但认为这是最好的例子,尽管高度不切实际,我如何更好地实现此目的以根据0-255的字节值设置变量。


3
C# 和 C 从名称和部分语法上看起来很相似,但我不会将它们归为一类。C# 和 Java 可能比 C# 和 C 更相似。在我看来,C# 的名称只是微软巧妙的营销策略。 - DAB
@DAB 是的,因为“ISO/IEC 23270:2006”这个名字听起来就不太好。:) - user
6个回答

12
使用按位与运算符(&)。假设Input0表示最低有效位:
IO.Input0 = (inputBuffer & 0x01) == 0x01;
IO.Input1 = (inputBuffer & 0x02) == 0x02;
IO.Input2 = (inputBuffer & 0x04) == 0x04;
IO.Input3 = (inputBuffer & 0x08) == 0x08;
IO.Input4 = (inputBuffer & 0x10) == 0x10;
IO.Input5 = (inputBuffer & 0x20) == 0x20;
IO.Input6 = (inputBuffer & 0x40) == 0x40;
IO.Input7 = (inputBuffer & 0x80) == 0x80;

你也可以实现一个类似以下的扩展方法:

public static bool IsBitSet(this byte b, int bit)
{
    if(bit < 0 || bit > 7)
        throw new ArgumentOutOfRangeException("bit must be between 0 and 7");

    byte bitToCheck = (byte)(0x01 << bit);

    return (b & bitToCheck) == bitToCheck;
}

然后您可以像这样调用:

IO.Input4 = inputBuffer.IsBitSet(4);

4
使用位掩码和 & 运算符来解决这个问题。
byte b = 100;

if(b&1 == 1) { } //bit 1 is set
if(b&2 == 2) { } //bit 2 is set
if(b&4 == 4) { } //bit 3 is set
...

在你进行编辑之前,代码是if(b&1) { } //bit 1 is set,但现在你已经进行了编辑并且现在它是正确的。 - Matthew Watson

2

我认为自己编写一个类可以帮助解决问题。这个类可以包含8位,构造函数需要传入一个字节(byte)。在构造函数中,您可以计算每一位的值。

public class myByte
{
    bool    Input0 = false;
    bool    Input1 = false;
    bool    Input2 = false;
    bool    Input3 = false;
    bool    Input4 = false;
    bool    Input5 = false;
    bool    Input6 = false;
    bool    Input7 = false;        

    public myByte(byte b)
    {
        //written by Ic.
        Input0 = b & 0x01 == 0x01;
        Input1 = b & 0x02 == 0x02;
        Input2 = b & 0x04 == 0x04;
        Input3 = b & 0x08 == 0x08;
        Input4 = b & 0x10 == 0x10;
        Input5 = b & 0x20 == 0x20;
        Input6 = b & 0x40 == 0x40;
        Input7 = b & 0x80 == 0x80;
    }
    ... //getter setter ...
}

2

你可以这样做。

int x= inputBuffer[1];

bit1 = ((x>>7)&1==1);
bit2 = ((x>>6)&1==1);
bit3 = ((x>>5)&1==1);
bit4 = ((x>>4)&1==1);
bit5 = ((x>>3)&1==1);
bit6 = ((x>>2)&1==1);
bit7 = ((x>>1)&1==1);
bit8 = (x&1==1);

要获得11101110值的第一个位,您需要将其向右移7次,然后使用AND操作与1进行比较,以确定该值是1还是0。其他位也适用相同的解决方案。

2
如果数据以字节形式提供给您,并且每个位都已屏蔽,则建议保留原样不用转换为其他类型。这样做没有任何好处,只会增加额外的工作。要获取正确的位,请使用位屏蔽模式。
private bool GetMaskedBit(var inputBuffer , int mask)
{
    return ((inputBuffer & mask) != 0);
}

通过解析缓冲区并获取所需的位,你可以判断该位是否被设置。


2
为什么不直接返回(inputBuffer & mask) != 0呢? - DaveDev
它们需要转换为每个输入的单独布尔变量,因为这会简化其他地方的事情。 - Tom Poulton

2
您可以使用 BitArray 类来完成此操作。
var bitArray = new BitArray(inputBuffer);
IO.Input1 = bitArray[byteIndex * 8 + 1];

或者

var bitArray = new BitArray(new byte[] { inputBuffer[1] });
IO.Input1 = bitArray[1];

你也可以将其作为布尔值的集合进行迭代,并对整个集合执行位运算。显然,这种方法的性能不如其他选项(分配成本),但它确实为位计算提供了非常简洁的API。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接