【问题标题】:How to set multiple bit values within an integer如何在整数内设置多个位值
【发布时间】:2016-04-01 20:54:13
【问题描述】:

我正在使用 Visual Studio 2015 在 vb.net 中编写程序。我试图弄清楚如何修改 16 位整数中的各个位。 numeric 数据类型的字节顺序是 little-Indian,如下所示:

  • 原点(2 位)
  • 标记(1 位)
  • 可寻址(1 位)
  • 协议(12 位)
Field:  [ origin ] [tagged] [addressable] [protocol]
Bits:    16 15      14       13            12 11 10 9 8 7 6 5 4 3 2 1

在下面的示例代码中,我试图弄清楚如何在 16 位整数变量“i”中设置来源、标记、可寻址和协议。

  Dim i As UInt16 = 0
  Dim origin As Byte = 0          ' Message origin indicator
  Dim tagged As Byte = 0          ' Determines usage of the Frame Address target field (0 or 1)
  Dim addressable As Byte = 0     ' Message includes a target address (0 or 1)
  Dim protocol As UInt16 = 1024   ' Protocol number: must be 1024 (decimal)

谁能提供一个 vb.net 示例,说明我如何更新变量“i”,使其包含来源、标记、可寻址和协议的位值?

【问题讨论】:

    标签: vb.net bit-manipulation bytearray bitwise-operators bit-shift


    【解决方案1】:

    您可以使用or 的组合来设置单个位,并使用>><< 来移动位。

    例如,要设置标记、可寻址和协议中的两个字节,您可以这样做:

    Dim tagged As Byte = 1          ' Determines usage of the Frame Address target field (0 or 1)
    Dim addressable As Byte = 1     ' Message includes a target address (0 or 1)
    Dim protocol As UInt16 = 1026   ' Protocol number: must be 1024 (decimal)
    
    sendbuf(0) = sendbuf(0) or tagged ' bit 0
    sendbuf(0) = sendbuf(0) or (addressable << 1) ' bit 1
    sendbuf(0) = sendbuf(0) or ((protocol << 2) and 255) ' first 6 bits of protocol
    
    sendbuf(1) = sendbuf(1) or (protocol >> 6) ' next 6 bits of protocol
    

    您可能需要调整它 - 我没有点击链接,所以我不完全确定哪些位应该放在哪里(有 14 位适合 2 个字节)。

    【讨论】:

      【解决方案2】:

      在枚举中使用二进制值映射位值。 1 = 1、2 = 10、4 = 100 等。然后您可以使用枚举分配变量。您还可以将这些值组合成一个新的枚举(参见 ProtocolX)。

      要给出初始值,只需添加要使用的枚举即可。

          ' switch bits on 1, 5, 13, 14, 16
          i = FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5 +
              FrameSectionEnum.AddressableBit13 +
              FrameSectionEnum.TaggedBit14 + FrameSectionEnum.OriginBit16
          PrintBits(i)
      

      要打开某些位并保留其他位,请使用 OR。

          ' switch bits on 2 and 3 using a combined value. preserve other bits
          i = SetOn(i, FrameSectionEnum.ProtocolX)
          PrintBits(i)
      

      要关闭某些位并保留其他位,请使用 AND 和 NOT。

          ' switch bits off 1 and 5
          i = SetOff(i, FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5)
          PrintBits(i)
      

      实用功能列表:

      检查某些位是否打开:

      Function CheckBit(i As Integer, bit As FrameSectionEnum) As Integer
          Return If((i And bit) = bit, 1, 0)
      End Function
      

      设置位,保留其他位:

      Function SetOn(i As Integer, bit As FrameSectionEnum) As Integer
          Return i Or bit
      End Function
      

      设置位关闭,保留其他位:

      Function SetOff(i As Integer, bit As FrameSectionEnum) As Integer
          Return i And (Not bit)
      End Function
      

      完整代码:

      Module Module1
      
          Enum FrameSectionEnum
              ProtocolBit1 = 1
              ProtocolBit2 = 2
              ProtocolBit3 = 4
              ProtocolBit4 = 8
              ProtocolBit5 = 16
              ProtocolBit6 = 32
              ProtocolBit7 = 64
              ProtocolBit8 = 128
              ProtocolBit9 = 256
              ProtocolBit10 = 512
              ProtocolBit11 = 1024
              ProtocolBit12 = 2048
      
              AddressableBit13 = 4096
      
              TaggedBit14 = 8192
      
              OriginBit15 = 16384
              OriginBit16 = 32768
      
              ProtocolX = ProtocolBit2 + ProtocolBit3
          End Enum
      
      
          Sub Main()
      
              Dim i As UInt16 = 0
              ' switch bits on 1, 5, 13, 14, 16
              i = FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5 +
                  FrameSectionEnum.AddressableBit13 +
                  FrameSectionEnum.TaggedBit14 + FrameSectionEnum.OriginBit16
              PrintBits(i)
      
              ' switch bits on 2 and 3 using a combined value. preserve other bits
              i = SetOn(i, FrameSectionEnum.ProtocolX)
              PrintBits(i)
      
              ' switch bits off 1 and 5
              i = SetOff(i, FrameSectionEnum.ProtocolBit1 + FrameSectionEnum.ProtocolBit5)
              PrintBits(i)
      
              Console.ReadKey(True)
      
          End Sub
      
          Function SetOn(i As Integer, bit As FrameSectionEnum) As Integer
              Return i Or bit
          End Function
      
          Function SetOff(i As Integer, bit As FrameSectionEnum) As Integer
              Return i And (Not bit)
          End Function
      
          Function CheckBit(i As Integer, bit As FrameSectionEnum) As Integer
              Return If((i And bit) = bit, 1, 0)
          End Function
      
          Sub PrintBits(i As Integer)
      
              Console.Write(CheckBit(i, FrameSectionEnum.OriginBit16))
              Console.Write(CheckBit(i, FrameSectionEnum.OriginBit15))
      
              Console.Write(CheckBit(i, FrameSectionEnum.TaggedBit14))
      
              Console.Write(CheckBit(i, FrameSectionEnum.AddressableBit13))
      
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit12))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit11))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit10))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit9))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit8))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit7))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit6))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit5))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit4))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit3))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit2))
              Console.Write(CheckBit(i, FrameSectionEnum.ProtocolBit1))
      
              Console.WriteLine()
      
          End Sub
      
      End Module
      

      【讨论】:

        【解决方案3】:

        问题中的标题格式包含将所有位放在正确位置的关键。就我个人而言,如果您使用从零开始的索引对位重新编号,则更容易可视化:

        Field:  [ origin ] [tagged] [addressable] [protocol]
        Bits:    15 14      13       12            11 10 9 8 7 6 5 4 3 2 1 0
        

        origin字段开始,需要左移14位,可以这样:

        origin << 14
        

        taggedaddressable 字段需要分别左移 13 位和 12 位,方法相同。 protocol 字段已经在正确的位置,因此不需要移动它。它们都可以与Or 运算符组合在一起,如下所示:

        i = (origin << 14) Or (tagged << 13) Or (addressable << 12) Or protocol
        

        最后一个需要解决的细节是,在 VB.NET 中,位移操作取决于被位移的数据类型。在上面的代码中,origintaggedaddressable 变量都是 Byte 类型。这种类型的移位都将以 8 为模(一个字节中的位数),这意味着 9 位的移位与 1 位的移位相同。

        因为我们所有的移位都超过 8 位,所以我们需要转换为更广泛的数据类型,否则事情将不会出现在正确的位置。最简单的方法是将所有变量的声明更改为UInt16

        Dim i As UInt16
        Dim origin As UInt16 = 0
        Dim tagged As UInt16 = 0
        Dim addressable As UInt16 = 0
        Dim protocol As UInt16 = 1024
        
        i = (origin << 14) Or (tagged << 13) Or (addressable << 12) Or protocol
        

        对此的替代方法是保持变量声明原样,并在执行移位之前使用CType 转换字段:

        Dim i As UInt16 = 0
        Dim origin As Byte = 0
        Dim tagged As Byte = 0
        Dim addressable As Byte = 0
        Dim protocol As UInt16 = 1024
        
        i = (CType(origin, UInt16) << 14) Or (CType(tagged, UInt16) << 13) Or (CType(addressable, UInt16) << 12) Or protocol
        

        就个人而言,由于简洁,我更喜欢第一种方式,但选择权在你!

        【讨论】:

          猜你喜欢
          • 2019-06-06
          • 1970-01-01
          • 2012-06-26
          • 2019-05-27
          • 1970-01-01
          • 2012-12-14
          • 2014-09-28
          • 1970-01-01
          • 2019-03-28
          相关资源
          最近更新 更多