如何在整数内设置多个位值

时间:2015-12-28 00:06:52

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

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

  • 原产地(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

在下面的示例代码中,我试图弄清楚如何在变量" i"中设置原点,标记,可寻址和协议。这是一个16位整数。

  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"这样它包含原点,标记,可寻址和协议的位值?

3 个答案:

答案 0 :(得分:0)

您可以使用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个字节)。 / p>

答案 1 :(得分:0)

使用枚举中的二进制值映射位值。 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

答案 2 :(得分:0)

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

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

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