C# 使用来自 "Bits" 的二进制运算构建整数值

C# Building a Integer value with Binary operations from "Bits"

我有一个字节数组,实际上是这样的二进制值

byte[] buf = new byte[] { 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

二进制表示为1111 1110 (0xFF = 0, 0xF0= 1).

需要由此构建的整数或字节的值为0xFE (254)。

我考虑过将 buf 转换为 10 的字符串,然后再转换回整数,但必须存在更优雅的方法来完成此操作二元运算。

已知可以完美执行此操作的 Pascal 代码是(使用字符串):

  if NumberOfBytes > 0  then begin    // there was a response
     for c := Length(Str) downto 1 do begin
        Ch := Str[c];
        if (ord(ch) AND 2) = 0 then begin
           Sin := Sin + '0';
        end else begin
           Sin := Sin + '1';
        end;
        INC(Teller);
        if (Teller mod 8) = 0 then begin
            N := BinaryStrToByte(Sin);
            Edit2.Text := Edit2.Text + ByteHex(N) + ' ' ;
            Sin := '';
        end;
     end;

还有 C 代码,由于行为上的一些差异,似乎无法移植到 C#:

for(bytes = 0; bytes < len; bytes++)
 {
   newByte=0;
   for(bits=0; bits<8; bits++)
   {
     newByte >>= 1;
    if(inBuf[0]==0xff) 
    {
      newByte |= 0x80;
    }
   }
   pBuf[bytes]=newByte;
 }

我想有效地遍历我的原始数组,然后将一个真正的二进制 01 放入 intbyte,这取决于我是否有当前位置的 0xF00xFF 值。

这可能会成功:

public static void Main()
{
    byte[] buf = new byte[] { 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    byte result = 0;
    foreach(var b in buf.Reverse())
    {
        result <<= 1;
        if(b == 0xFF) result |= 1;
    }
    Console.WriteLine(result);
}

具有最少分支(和 LINQ 调用)的方法:

byte result = 0x00;
foreach(byte b in buf) {
    result >>= 0x01;
    byte bs = b;
    bs <<= 0x07;
    result |= bs;
}

此代码假设每个字节的最低有效位确定 0(在 0xf0=1111 0000 的情况下)是 1(在 0xff=1111 1111 的情况下) ) 应添加。

Mono C# Interactive 中的演示 shell:

csharp> byte[] buf = new byte[] { 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
csharp> byte result = 0x00;
csharp> foreach(byte b in buf) {
      >     result >>= 0x01;
      >     byte bs = b;
      >     bs <<= 0x07;
      >     result |= bs;
      > }
csharp> result.ToString("X");
"FE"

这里有一些更通用的类似 LINQ 的解决方案:

将字节转换为位的方法(在本例中表示为布尔值)

public static IEnumerable<Boolean> BytesToBooleans(IEnumerable<Byte> bytes)
{
    if (bytes == null)
        throw new ArgumentNullException("bytes");

    return bytes
        .Select(b =>
            {
                if (b == 0xF0)
                    return false;
                if (b == 0xFF)
                    return true;
                throw new ArgumentException();
            });
}

将布尔值解释为从最低位开始的位的方法:

public static IEnumerable<Byte> BooleansAsBitsFromLowest(this IEnumerable<Boolean> bits)
{
    if (bits == null)
        throw new ArgumentNullException("bits");

    Int32 bitsInByte = 0;
    Byte curByte = 0;

    foreach (var bit in bits)
    {
        var mask = (Byte)(bit ?
            0x1 : 0x0);

        mask = (Byte)(mask << bitsInByte);

        curByte |= mask;
        bitsInByte++;

        if (bitsInByte == 8)
        {
            yield return curByte;
            curByte = 0;
            bitsInByte = 0;
        }
    }

    if (bitsInByte != 0)
        yield return curByte;
}

这是用法:

byte[] buf = new byte[] { 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };

var bytesFromBits = BytesToBooleans(buf)
    .BooleansAsBitsFromLowest();

foreach (var resultingByte in bytesFromBits)
{
    Console.WriteLine(resultingByte.ToString("X2"));
}