Aaron Summernite
Aaron Summernite

Reputation: 365

Bitwise operations, combining 3 bytes to long

I am trying to combine three Byte values to one Long value, like System.Drawing.Color.ToArgb() does.

I've looked up reference source code to find it and converted it to VB .NET:

Return CLng((CInt(red) << 16 Or CInt(green) << 8 Or blue Or CInt(alpha) << 24) And -1)

It works fine of course, but I don't really understand why alpha shifted by 24 is last, not first (so it would be in nice order 24, 16, 8). I don't really understand bitwise operations a lot. Also, this code snippet works for 4 bytes, which is redundant for me, I need just three bytes and I wonder if Long is still required when bytes are only three, wouldn't Integer do just fine in this case?

So, my question is, how do I rewrite this code to work with just 3 parameters? Do I need to use Long? And, I know this is silly, but is it possible to make byte shifting in order 16,8,0 instead of 16,8,0,24? It's really just aesthetics, but I am awful perfectionist.

Thanks in advance!

Aaron

Upvotes: 0

Views: 1848

Answers (3)

Gil.I
Gil.I

Reputation: 884

I'm not familiar with VB.NET, but in general there is no right or wrong order of the shift count. It can be 24, 16, 8, 0 or 16, 24, 0, 8 or any other order.

And regrading the variable type: There are 8-bit, 16-bit and 32-bit variables. That means you must define a 32-bit type (long) in order to have room for your three bytes. For easy access, leave the 8 MSB bits as 0 so you can use it as a 24-bit value (0x00YYYYYY).

Upvotes: 1

Hans Passant
Hans Passant

Reputation: 941605

It doesn't matter, a OR b is the same value as b OR a. The OR operator is commutative, just like the + and * operators.

An Integer can store the value just fine, it has 32 bits. Using UInteger instead can be useful to deal with alpha values larger than 127 turning the value negative. Which will give you a bit of a headache when you try to read the alpha value back. Sign extension produces a large value, fixed by AND-ing with 255. Long was common in VB6 code since its Integer type had only 16 bits, not an issue in vb.net.

Upvotes: 1

dbasnett
dbasnett

Reputation: 11773

Here are some different ways. The order of the OR's does not matter. I added some debugs so you can see the results as you go.

Private Sub Button1_Click(sender As System.Object, _
                          e As System.EventArgs) Handles Button1.Click

    Dim bar As Integer '32 bits

    'three byte values
    Dim x As Byte = 66
    Dim y As Byte = 65
    Dim z As Byte = 82

    'desired byte order
    '0xyz

    'one byte at a time
    bar = 0
    bar = bar Or (CInt(x) << 16)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))
    bar = bar Or (CInt(y) << 8)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))
    bar = bar Or (CInt(z) << 0) 'bar Or CInt(z)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'or as single statement
    bar = 0 Or (CInt(x) << 16) Or (CInt(y) << 8) Or CInt(z)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'in any order
    bar = 0 Or CInt(z) Or (CInt(y) << 8) Or (CInt(x) << 16)
    Debug.WriteLine(Convert.ToString(bar, 2).PadLeft(32, "0"c))

    'check results
    Dim foo() As Byte = BitConverter.GetBytes(bar) 'get the individual bytes
    Array.Reverse(foo) 'reverse
    Debug.WriteLine(System.Text.ASCIIEncoding.ASCII.GetChars(foo, 1, 3))
End Sub

Upvotes: 1

Related Questions