【问题标题】:C# Building a Integer value with Binary operations from "Bits"C# 使用“位”中的二进制运算构建整数值
【发布时间】:2015-05-31 02:22:11
【问题描述】:

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

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

二进制表示为1111 11100xFF = 0, 0xF0= 1)。

需要从中构建的整数或字节的值是0xFE (254)。

我曾考虑将buf 转换为1s 和0s 的字符串,然后再转换为整数,但必须存在更优雅的方法来通过二进制操作完成此操作。

已知可以完美执行此操作的 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 值当前位置。

【问题讨论】:

  • 看看BitConverter-class。
  • 呃——你说 "二进制表示是 1111 1110 (FF = 0, F0= 1)" 这很令人困惑。你的意思是说:“二进制表示是 1111 1111 1111 1110(其中第一个和第二个字节已交换,因此 x'FF' 值为 position = 0,而 x'F0' 为位置 = 1)" ???
  • 您是否要求人们为您编写代码?您的问题是什么?
  • 是的,听起来确实令人困惑,但我正在与之通信的硬件通过串行端口将二进制数据返回给我,FF 表示 0,F0 表示 1,我必须将其转换为真正的二进制值首先,然后我可以使用 BitConverter 来解析它...
  • @EricLippert 我的问题是:我想有效地循环遍历我的原始数组,然后将真正的二进制 0 或 1 放入 Integer 或 byte 中,这取决于我是否有 F0 或 FF 值当前位置。

标签: c# binary integer-arithmetic


【解决方案1】:

这可能会奏效:

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

【讨论】:

  • 也许您可以将result = (byte)(result &lt;&lt; 1); 替换为result &lt;&lt;= 1;,这样可以节省转换并使其更具可读性。
  • 这 100% 有效,我仍然无法理解为什么 C 示例不想在 C# 的直接端口中完成其工作。非常干净的解决方案:)
  • @NxtLevel:问题可能出在inBuf[0],这里你总是取第一个元素。你确定例如 C 代码不会增加指针吗?
【解决方案2】:

一种具有最少分支(和 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"

【讨论】:

    【解决方案3】:

    这里有一个更通用的类似 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"));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-03
      • 2021-09-11
      • 2014-06-25
      • 2020-10-31
      • 2021-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多