【问题标题】:Copy bits in correct order以正确的顺序复制位
【发布时间】:2022-04-25 18:42:16
【问题描述】:

为了解析非托管数据的二进制流,我必须重新创建数据类型。数据被压缩,这意味着我读取了 2 个字节,它们实际上代表一个 6 位 byte 值和一个 10 位 short 值。

我需要做的就是将一个位序列从一个值复制到另一个值。我知道源值和目标值的起始位和长度。到目前为止,我已经提出了两种方法,它们都复制了正确的位,但不知何故以相反的顺序。

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
{
    short result = 0;
    for (int i = 0; i < bitCount; i++)
        //result |= (byte) (value & (1 << sourceStartBit + i) | (result & (1 << (destStartBit + bitCount) - i)));
        result |= (short) (value & (1 << sourceStartBit + i));

    return (byte) (result >> ((destStartBit - bitCount) + sizeof(byte) * 8));
}

对于我的测试场景,我使用的是具有以下值的 short:

0000 0000 1101 0011
^15               ^0

我的目标是将这个短的 4-th - 7-th 位复制到一个字节的 0-3rd 位。

当我使用注释行(没有返回子句中的代码)方法或当前突出显示的方式时,我总是得到这个结果:

0000 1011
^7      ^0

所以我想要的,只是颠倒了。我敢肯定它很小,但我在这里俯瞰什么?我不明白为什么它会颠倒顺序。移位方法(直接按位复制并将其移动到正确的位置)不应该颠倒它,不是吗?

编辑always 方法有一个short 类型的输入。我有 3 个参数: sourceStart 这是我开始从输入值(低到高)复制的位,destStart 这是我复制到目标的位(这是字节或短 - 我会为此制定两种特定方法)和 bitCount 这是我要复制的位数(从低位到高位)。

该方法必须以正确的顺序复制位。因此,例如CopyBitwise(input, 4, 0, 4) 应该返回(左:高,右:低顺序)0000 1011 给定这个输入:

input [short]: ... 1011 0110
                   ^8th    ^0th

另一个:

input [short]: 1011 0110 0100 0111
               ^15th             ^0th
                    ^end ^start

CopyBitwise(input, 7, 3, 5) 应该会导致

0011 0000
^8th    ^0th
^end ^start

【问题讨论】:

  • 您的输入到底是什么,您的预期输出到底是什么?
  • 输入总是一个短的,我必须分成一个字节和另一个短值。我想要一个通用方法,它从输入中获取从 sourceStart 开始的 n 个字节,并将其复制到 destStart 处的目标字节/短相同的顺序。
  • 您应该清楚地列出给定输入值的输出字节和短字节应该是什么。我也还不清楚。添加更多示例以避免混淆。
  • 你的代码没有帮助解释,这不应该需要for循环。
  • '非托管数据'不是真实的。文件中的字节序是这里的一个主要问题。清楚地表明你是如何阅读这篇文章的(阅读shortbyte[2] 是不一样的)。

标签: c# bitwise-operators bit-shift


【解决方案1】:

您不需要循环! 这应该可以解决问题:

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount){
    byte result = (byte) ((value >> sourceStartBit) << destStartBit);
    result &= (byte) ~(0xff << bitCount); // mask for zeros at the left of result
    return result;
}

【讨论】:

  • 编译的代码更有可能获得支持并被标记为正确。否则是一种改进的方式来做 OP 想要的事情。
  • 是的,非常感谢您。由于它对性能至关重要,因此这种方式会更好。尽管如此,PaulF 是对的,但它不是这样编译的。
【解决方案2】:

这应该可以正常工作。 首先为您需要的位创建一个掩码,然后将它们移动到所需的位置。请注意,移位是分两次完成的,因为移位运算符必须是正数。

byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
{
  short mask = (short)((0xFFFF >> (16-bitCount)) << sourceStartBit);
  short result = (short)(((value & mask) >> sourceStartBit) << destStartBit);
  return (byte)result;
}

【讨论】:

    【解决方案3】:

    听起来你想要的是剪掉给定短片的子序列。这可以通过屏蔽来实现。如果您想从以下位序列中删除突出显示的位:1011 0110 0100 0111,您可以通过&amp;ing 来实现0000 0000 1111 0000

      1011 0110 0100 0111
    & 0000 0000 1111 0000
    = 0000 0000 0100 0000
    

    然后您可以移动结果位,以便您的屏蔽位从所需位置(此处为 1)开始:

      0000 0000 0100 0000 >>
     · 0000 0000 0100 000 >>
     ·· 0000 0000 0100 00 >>
     ··· 0000 0000 0100 0
    

    为了更具体,这里有一些代码:

    byte BitwiseCopy(short value, int sourceStartBit, int destStartBit, int bitCount)
    {
        ushort mask = 0; //Start with 0
        mask = (ushort)~mask; //Invert to get all 1s
        mask >>= sizeof(ushort)*8 - bitCount; //Shift right, until we have bitCount bits left
        mask <<= sourceStartBit; //Shift back left, to make sure the bits are in the right place
        
        ushort result = (ushort)value;
        result &= mask; //Mask out the bits we want
        
        //Shift the remaining bits into the desired position
        if (sourceStartBit < destStartBit)
        {
            result <<= destStartBit - sourceStartBit;
        }
        else
        {
            result >>= sourceStartBit - destStartBit;
        }
        return (byte)result;
    }
    

    代码分解:

    首先,我们组装位掩码。为此,我们从0 开始,然后反转所有位以得到所有位。我们可以从0xFFFF 开始,但是如果您切换到不同长度的输入,这样代码仍然可以工作。

    然后我们移动我们的掩码直到只剩下bitCount1s。对于这一步,重要的是我们的掩码是 unsigned 整数类型。如果您使用有符号值,则位移会从左侧移入新的1s。

    为了完成我们的面具,我们将它向左移动以正确定位。

    接下来,我们将掩码应用于我们的值,以删除我们不想要的位。

    最后,我们将结果移动到所需的位置;这里再次重要的是使用 unsigned 移位,以确保没有错误的 1s 从左侧移入。


    以下是使用参数调用方法时发生的示例 (0b1011_0110_0100_0111, 7, 3, 5),就像你的第二个例子一样。

    mask:
      0000 0000 0000 0000  ~x
    = 1111 1111 1111 1111  x>>(16 - 5)
    = 0000 0000 0001 1111  x<<7
    = 0000 1111 1000 0000
    
    result:
      1011 0110 0100 0111  x&mask
      0000 0110 0000 0000  x>>(7-3)
      0000 0000 0110 0000
    

    编辑 1: 将代码中的这一行 mask &gt;&gt;= bitCount - sizeof(ushort)*8; 更正为 mask &gt;&gt;= sizeof(ushort)*8 - bitCount;

    编辑 2: 我也把下面的线弄乱了,也修好了。这就是我只测试一个案例所得到的结果。

    编辑 3: 添加了分步示例。

    【讨论】:

    • 一些 C# 代码在这里会很有用,但您没有考虑到如果源起始位小于目标起始位,则数据需要左移。
    • 您是否对此进行了测试以查看它是否从 OP 示例中获得了预期结果
    【解决方案4】:

    我从上面改进了 BitWiseCopy 方法,这样您不仅可以将位复制到空/新字节中,还可以复制到现有(目标)中。

    在本例中,我想将 3 位 (bitCount=3) 从位 #4 (sourceStartBit) 复制到位 #3 (destinationStartBit)。请注意,位的编号从“0”开始,在我的方法中,编号从最高有效位 = 0 开始(从左到右读取)。

    byte source = 0b10001110;
    byte destination = 0b10110001;
    
    byte result = CopyByteIntoByte(source, destination, 4, 1, 3);
    Console.WriteLine("The binary result: " + Convert.ToString(result, toBase: 2));
    //The binary result: 11110001
    
    byte CopyByteIntoByte(byte sourceByte, byte destinationByte, int sourceStartBit, int destStartBit, int bitCount)
    {
        int[] mask = { 0, 1, 3, 7, 15, 31, 63, 127, 255 };
        byte sourceMask = (byte)(mask[bitCount] << (8 - sourceStartBit - bitCount));
        byte destinationMask = (byte)(~(mask[bitCount] << (8-destStartBit - bitCount)));
        byte destinationToCopy = (byte)(destinationByte & destinationMask);
        int diff = destStartBit - sourceStartBit;
        byte sourceToCopy;
        if(diff > 0)
        {
            sourceToCopy = (byte)((sourceByte & sourceMask) >> (diff));
        }
        else
        {
            sourceToCopy = (byte)((sourceByte & sourceMask) << (diff * (-1)));
        }
        return (byte)(sourceToCopy | destinationToCopy);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多