Results 1 to 16 of 16

Thread: [RESOLVED] Bit conversion operations

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Resolved [RESOLVED] Bit conversion operations

    Hello everyone.

    In my API class I encountered a lot of times I had to Get/Set low/high order <something> of <something>. For example, get the low order integer from a long. I made a few functions for this:

    Code:
        Public Shared Function LHByteCombine(ByVal low As Byte, ByVal high As Byte) As Short
            Return low + high * 2 ^ 8
        End Function
        Public Shared Function LHShortCombine(ByVal low As Short, ByVal high As Short) As Integer
            Return low + high * 2 ^ 16
        End Function
        Public Shared Function LHIntegerCombine(ByVal low As Integer, ByVal high As Integer) As Long
            Return low + high * 2 ^ 32
        End Function
        Public Shared Function GetHighByte(ByVal value As Short) As Byte
            Return value >> 8
        End Function
        Public Shared Function GetHighShort(ByVal value As Integer) As Short
            Return value >> 16
        End Function
        Public Shared Function GetHighInteger(ByVal value As Long) As Integer
            Return value >> 32
        End Function
        Public Shared Function GetLowByte(ByVal value As Short) As Byte
            Return value - GetHighByte(value) * 2 ^ 8
        End Function
        Public Shared Function GetLowShort(ByVal value As Integer) As Short
            Return value - GetHighShort(value) * 2 ^ 16
        End Function
        Public Shared Function GetLowInteger(ByVal value As Long) As Integer
            Return value - GetHighInteger(value) * 2 ^ 32
        End Function
    Before I start using these functions permanently, I come to ask if it contains any bugs, especially because of the Unsigned/Signed issue.

  2. #2
    I'm about to be a PowerPoster! kleinma's Avatar
    Join Date
    Nov 2001
    Location
    NJ - USA (Near NYC)
    Posts
    23,373

    Re: Bit conversion operations

    You are not coding with option strict on. If you turned it on, you would see none of the methods compile because you are using narrowing conversions on the numeric values. With strict off, the runtime tries to perform the conversion for you, but this can lead to you assuming things are correct when in fact they could be wrong.

    For example, try running this:

    Code:
            Try
                Dim myShort As Short = CombineLH(Byte.MaxValue, Byte.MaxValue)
            Catch ex As Exception
                MessageBox.Show(ex.Message)
            End Try

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,109

    Re: Bit conversion operations

    I thought there was an issue with your GetHigh methods, but if you do the proper conversion, as Kleinma suggested, it will be ok.
    My usual boring signature: Nothing

  4. #4
    I'm about to be a PowerPoster! kleinma's Avatar
    Join Date
    Nov 2001
    Location
    NJ - USA (Near NYC)
    Posts
    23,373

    Re: Bit conversion operations

    Quote Originally Posted by Shaggy Hiker View Post
    I thought there was an issue with your GetHigh methods, but if you do the proper conversion, as Kleinma suggested, it will be ok.
    I thought maybe the GetHigh method would make everything really slow and make the app memory hungry

  5. #5

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Bit conversion operations

    Thanks for the replies.
    Updated the first post so no narrowing conversions take place.

    I had it like that before, but noticed that it was able to do the narrowing itself so left it out. (it called the GetLow byte version when two bytes were passed.)
    But I can understand that narrowing numeric values can cause some issues and it would be annoying if you find it out after you made everything around it.

    What about the UShort - Short, UInteger - Integer and ULong - Long conversions? I believe the signed versions have a bit set indicating negative/positive. Can that be of any problem when using these functions?

    EDIT

    Ow and does changing:
    Code:
    Return value >> 8
    To:
    Code:
    Return CByte(value >> 8)
    Improve the code or would the implicit conversion do the same thing anyways?

  6. #6
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,109

    Re: Bit conversion operations

    Quote Originally Posted by kleinma View Post
    I thought maybe the GetHigh method would make everything really slow and make the app memory hungry


    I can't believe I missed that.



    Implicit narrowing conversions will happen with Option Strict OFF, but even though they can be done, they are also slow, so don't do them. The speed difference is negligible if you are only calling a few of these, but bit manipulation is something you tend to do lots of if you do it at all, so a bit of attention to this detail will probably pay off, perhaps even noticeably.

    The signed versions don't really use a bit to indicate negative. You could look up Twos Complement for an in depth explanation of how negative numbers or stored, or Threes Company for a light commentary on the 70s. However, the net result (or the .NET result, anyways) of the Twos Complement way of storing numbers is that the high bit will be set for negative numbers. One interesting feature of .NET is that when you use the bit shift operator (>>), the most significant bit is propagated over. In C++, the >> operator shifts to the right and fills the high bits with 0. In .NET, the >> operator shifts to the right and fills the top bits with whatever was originally in the most significant bit. In your case, however, this will have no impact, because you are shifting over by a number of bytes, and throwing out the top bytes. If you were not shifting by multiples of 8, or were retaining the most significant bits, then you would have a problem. For example, if your GetHigh returned the same type as the argument rather than a type half the size of the argument, then you would certainly have an issue. You might actually consider doing this. After all, a 32 bit processor handles 32 bit values most efficiently. Therefore, shortening an Integer to a Short doesn't buy you much of anything. You could leave it as an integer, but if you did, you'd have to mask off the high bytes:
    Code:
    Public Function GetHigh(myInt As Integer) As Integer
     return ((myInt >>16) And &HFFFF)
    End Function
    My usual boring signature: Nothing

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Bit conversion operations

    Aah so THAT is why those functions on the internet use [& &HFFFF].

    But I prefer keeping the conversions, since I will be using the same functions in API's. For example, get the integer of a short and two bytes combined:
    Code:
    Dim flags As Integer = LHShortCombine(myshort, LHByteCombine(mybyte1, mybyte2))
    BTW: I used a bitconverter-method before, but I read everywhere that it is significantly slower. Here the (probably narrowing conversion sensitive) functions I used previously:
    Code:
        Public Shared Function GetBytes(ByVal ParamArray values() As Object) As Byte()
            Dim b As New List(Of Byte)
            For Each value As Object In values
                If TypeOf value Is Byte Then
                    b.Add(value)
                Else
                    b.AddRange(BitConverter.GetBytes(value))
                End If
            Next
            Return b.ToArray
        End Function
        Public Shared Function GetShort(ByVal l As Byte, ByVal h As Byte) As Short
            Return BitConverter.ToInt16(GetBytes(l, h), 0)
        End Function
        Public Shared Function GetInteger(ByVal ParamArray values() As Object) As Integer
            Return BitConverter.ToInt32(GetBytes(values), 0)
        End Function
    I had to use a lot of 'CTyping' because most passed values were enumerated values of type <>.

    Basically, I have to pass variables (LParam most of the time) that contain other values inside. I do not want to go with making structures for every single "Type" of LParam but want to "Combine" values of different types into the LParam. This can either be done with that "GetBytes -> Integer" method or by using multiple 'combine and convert' and splitting functions.

  8. #8
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Bit conversion operations

    By the way, there's a very easy way to convert between things with, for example, this 8-byte type: (Assumes Imports System.Runtime.InteropServices)
    Code:
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure XLong
         <FieldOffset(0)> Public UnsignedLongValue As ULong
         <FieldOffset(0)> Public LongValue As Long
         <FieldOffset(0)> Public HighInt As Integer
         <FieldOffset(4)> Public LowInt As Integer
         <FieldOffset(0)> Public Short1 As Short
         <FieldOffset(2)> Public Short2 As Short
         <FieldOffset(4)> Public Short3 As Short
         <FieldOffset(6)> Public Short4 As Short
         <FieldOffset(0)> Public Byte1 As Byte
         <FieldOffset(1)> Public Byte2 As Byte
         <FieldOffset(2)> Public Byte3 As Byte
         <FieldOffset(3)> Public Byte4 As Byte
         <FieldOffset(4)> Public Byte5 As Byte
         <FieldOffset(5)> Public Byte6 As Byte
         <FieldOffset(6)> Public Byte7 As Byte
         <FieldOffset(7)> Public Byte8 As Byte
    End Structure
    This allows you to get and set any bytes, shorts, ints, or longs in an 8-byte value. It's also very efficient.

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Bit conversion operations

    Interesting...but there are no problems if I would, for example, send such a structure instead of a long? And what if you have to retrieve the values from the LParam if you know that the order is short-byte-byte? Not sure what happens if you would use such a structure in a ByRef.

    EDIT

    Plus I would preferably make all members hidden and use properties with an index variable instead:
    vb Code:
    1. <StructLayout(LayoutKind.Explicit)> _
    2.     Public Structure XLong
    3.         <FieldOffset(0)> Private ULong1 As ULong
    4.         <FieldOffset(0)> Private Long1 As Long
    5.         <FieldOffset(0)> Private Integer1 As Integer
    6.         <FieldOffset(4)> Private Integer2 As Integer
    7.         <FieldOffset(0)> Private Short1 As Short
    8.         <FieldOffset(2)> Private Short2 As Short
    9.         <FieldOffset(4)> Private Short3 As Short
    10.         <FieldOffset(6)> Private Short4 As Short
    11.         <FieldOffset(0)> Private Byte1 As Byte
    12.         <FieldOffset(1)> Private Byte2 As Byte
    13.         <FieldOffset(2)> Private Byte3 As Byte
    14.         <FieldOffset(3)> Private Byte4 As Byte
    15.         <FieldOffset(4)> Private Byte5 As Byte
    16.         <FieldOffset(5)> Private Byte6 As Byte
    17.         <FieldOffset(6)> Private Byte7 As Byte
    18.         <FieldOffset(7)> Private Byte8 As Byte
    19.         Public Property ByteMember(ByVal index As Integer) As Byte
    20.             Get
    21.                 Select Case index
    22.                     Case 0
    23.                         Return Me.Byte1
    24.                     Case 1
    25.                         Return Me.Byte2
    26.                     Case 2
    27.                         Return Me.Byte3
    28.                     Case 3
    29.                         Return Me.Byte4
    30.                     Case 4
    31.                         Return Me.Byte5
    32.                     Case 5
    33.                         Return Me.Byte6
    34.                     Case 6
    35.                         Return Me.Byte7
    36.                     Case 7
    37.                         Return Me.Byte8
    38.                     Case Else
    39.                         Return Nothing
    40.                 End Select
    41.             End Get
    42.             Set(ByVal value As Byte)
    43.                 Select Case index
    44.                     Case 0
    45.                         Me.Byte1 = value
    46.                     Case 1
    47.                         Me.Byte2 = value
    48.                     Case 2
    49.                         Me.Byte3 = value
    50.                     Case 3
    51.                         Me.Byte4 = value
    52.                     Case 4
    53.                         Me.Byte5 = value
    54.                     Case 5
    55.                         Me.Byte6 = value
    56.                     Case 6
    57.                         Me.Byte7 = value
    58.                     Case 7
    59.                         Me.Byte8 = value
    60.                 End Select
    61.             End Set
    62.         End Property
    63.         Public Property ShortMember(ByVal index As Integer) As Short
    64.             Get
    65.                 Select Case index
    66.                     Case 0
    67.                         Return Me.Short1
    68.                     Case 1
    69.                         Return Me.Short2
    70.                     Case 2
    71.                         Return Me.Short3
    72.                     Case 3
    73.                         Return Me.Short4
    74.                     Case Else
    75.                         Return Nothing
    76.                 End Select
    77.             End Get
    78.             Set(ByVal value As Short)
    79.                 Select Case index
    80.                     Case 0
    81.                         Me.Short1 = value
    82.                     Case 1
    83.                         Me.Short2 = value
    84.                     Case 2
    85.                         Me.Short3 = value
    86.                     Case 3
    87.                         Me.Short4 = value
    88.                 End Select
    89.             End Set
    90.         End Property
    91.         Public Property IntegerMember(ByVal index As Integer) As Integer
    92.             Get
    93.                 Select Case index
    94.                     Case 0
    95.                         Return Me.Integer1
    96.                     Case 1
    97.                         Return Me.Integer2
    98.                     Case Else
    99.                         Return Nothing
    100.                 End Select
    101.             End Get
    102.             Set(ByVal value As Integer)
    103.                 Select Case index
    104.                     Case 0
    105.                         Me.Integer1 = value
    106.                     Case 1
    107.                         Me.Integer2 = value
    108.                 End Select
    109.             End Set
    110.         End Property
    111.         Public Property LongMember() As Long
    112.             Get
    113.                 Return Me.Long1
    114.             End Get
    115.             Set(ByVal value As Long)
    116.                 Me.Long1 = value
    117.             End Set
    118.         End Property
    119.         Public Property ULongMember() As ULong
    120.             Get
    121.                 Return Me.ULong1
    122.             End Get
    123.             Set(ByVal value As ULong)
    124.                 Me.ULong1 = value
    125.             End Set
    126.         End Property
    127.     End Structure

  10. #10
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Bit conversion operations

    No, here's how you use it:
    Code:
    ' To retrieve something from LParam with order short-byte-byte
    Dim v As XLong
    v.LowInt = theLParam
    Dim theHighShort As Short = v.Short3
    Dim theBytes() As Byte = {v.Byte7, v.Byte8}
    ' Do stuff
    And that in reverse to set things. When you want to transfer its Long value to a function, instead pass theVariable.LongValue.

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: Bit conversion operations

    Hey never thought of that
    Thanks, I guess I will be using this, or a somewhat modified version.
    (like adding constructors to hold a certain value at start)

    I always thought the <offset> thing only allowed a certain row of values, didn't know the values actually shared their bytes! Another thing learned.

    EDIT

    Final code:
    vb Code:
    1. <StructLayout(LayoutKind.Explicit)> _
    2.     Public Structure WORD
    3.         <FieldOffset(0)> Public Short1 As Short
    4.         <FieldOffset(0)> Public UShort1 As UShort
    5.         <FieldOffset(0)> Public Byte1 As Byte
    6.         <FieldOffset(1)> Public Byte2 As Byte
    7.     End Structure
    8.     <StructLayout(LayoutKind.Explicit)> _
    9.     Public Structure DWORD
    10.         <FieldOffset(0)> Public Integer1 As Integer
    11.         <FieldOffset(0)> Public UInteger1 As UInteger
    12.         <FieldOffset(0)> Public Short1 As Short
    13.         <FieldOffset(0)> Public UShort1 As UShort
    14.         <FieldOffset(2)> Public Short2 As Short
    15.         <FieldOffset(2)> Public UShort2 As UShort
    16.         <FieldOffset(0)> Public Byte1 As Byte
    17.         <FieldOffset(1)> Public Byte2 As Byte
    18.         <FieldOffset(2)> Public Byte3 As Byte
    19.         <FieldOffset(3)> Public Byte4 As Byte
    20.     End Structure
    21.     <StructLayout(LayoutKind.Explicit)> _
    22.     Public Structure QWORD
    23.         <FieldOffset(0)> Public Long1 As Long
    24.         <FieldOffset(0)> Public ULong1 As ULong
    25.         <FieldOffset(0)> Public Integer1 As Integer
    26.         <FieldOffset(0)> Public UInteger1 As UInteger
    27.         <FieldOffset(4)> Public Integer2 As Integer
    28.         <FieldOffset(4)> Public UInteger2 As UInteger
    29.         <FieldOffset(0)> Public Short1 As Short
    30.         <FieldOffset(0)> Public UShort1 As UShort
    31.         <FieldOffset(2)> Public Short2 As Short
    32.         <FieldOffset(2)> Public UShort2 As UShort
    33.         <FieldOffset(4)> Public Short3 As Short
    34.         <FieldOffset(4)> Public UShort3 As UShort
    35.         <FieldOffset(6)> Public Short4 As Short
    36.         <FieldOffset(6)> Public UShort4 As UShort
    37.         <FieldOffset(0)> Public Byte1 As Byte
    38.         <FieldOffset(1)> Public Byte2 As Byte
    39.         <FieldOffset(2)> Public Byte3 As Byte
    40.         <FieldOffset(3)> Public Byte4 As Byte
    41.         <FieldOffset(4)> Public Byte5 As Byte
    42.         <FieldOffset(5)> Public Byte6 As Byte
    43.         <FieldOffset(6)> Public Byte7 As Byte
    44.         <FieldOffset(7)> Public Byte8 As Byte
    45.     End Structure

    Just wondering though...could you store Byte1...Byte8 as an array (of 8 elements) or would that interfere with the Marshalling too much?

    E.g.
    vb Code:
    1. <StructLayout(LayoutKind.Explicit)> _
    2.     Public Structure QWORDA
    3.         <FieldOffset(0)> Public Longs() As Long
    4.         <FieldOffset(0)> Public ULongs() As ULong
    5.         <FieldOffset(0)> Public Integers() As Integer
    6.         <FieldOffset(0)> Public UIntegers() As UInteger
    7.         <FieldOffset(0)> Public Shorts() As Short
    8.         <FieldOffset(0)> Public UShorts() As UShort
    9.         <FieldOffset(0)> Public Bytes() As Byte
    10.     End Structure

  12. #12
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: [RESOLVED] Bit conversion operations

    I've been using something similar to Minitech there, and just want to confirm it appears very efficient.
    W o t . S i g

  13. #13
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: [RESOLVED] Bit conversion operations

    I don't know; I've never tried. Marshal.Copy seems to handle them pretty well though, and array elements should be stored sequentially in memory so that is a possibility.

    No wait, it's not possible - the structure could never know the size of the array ahead of time. You would store a POINTER to the array which would really mess things up for you. On a 64-bit system, the LongValue would be a pointer to the array and on a 32-bit system half of it would be zeroes. Don't do that.

  14. #14

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: [RESOLVED] Bit conversion operations

    Okay, I'll keep the large amounts of members then.
    Might add some properties to them like "Bytes(Integer index, Integer count) As Byte()", but I'm not sure. Thanks for the help everyone, really didn't expect that this would have been a possibility.

    And yep, it looks very slim. For example, the following function:
    Code:
            Private Shared Function GetErrorString(ByVal ErrorCode As Long) As String
                With New QWORD(ErrorCode)
                    GetErrorString = "Device " & .Integer2 & " - "
                    Dim buff As New System.Text.StringBuilder(128)
                    If mciGetErrorString(.Integer1, buff, buff.Capacity) Then
                        GetErrorString &= buff.ToString
                    Else
                        GetErrorString &= "Error code: " & .Integer1
                    End If
                End With
            End Function

  15. #15
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: [RESOLVED] Bit conversion operations

    In c# you can define a sequential sequence of a type within a structure using the fixed keyword but this is considered unsafe and so I assume not an option in VB.
    W o t . S i g

  16. #16

    Thread Starter
    Fanatic Member
    Join Date
    Jul 2009
    Posts
    629

    Re: [RESOLVED] Bit conversion operations

    Ow I found it no problem having all those members in the end, it is actually pretty useful having all these members ready to access in one go.

    For example, I added a CType conversion from "WORD to Short", "DWORD to Integer" and "QWORD to Long" and can now pass my structure into functions that require a Short/Integer/Long parameter. Plus some "FromXXXX" functions:
    Code:
            Public Shared Function FromSBB(ByVal Short1 As Short, ByVal Byte1 As Byte, ByVal Byte2 As Byte) As DWORD
                FromSBB = New DWORD
                FromSBB.Short1 = Short1
                FromSBB.Byte3 = Byte1
                FromSBB.Byte4 = Byte2
            End Function
    This must be the easiest order conversion I ever did.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width