Bitwise Operations in VB.NET

How to work with the 1's and 0's

VB.NET doesn't support bit level operations directly. Framework 1.1 (VB.NET 2003) introduced bit shift operators (<< and >>), but no general purpose way to manipulate individual bits is available. Bit operations can be very useful. For example, your program might have to interface with another system that requires bit manipulation. But in addition, there are a lot of tricks that can be done using individual bits.

This article surveys what can be done with bit manipulation using VB.NET.

You need to understand bitwise operators before anything else. In VB.NET, these are:

  • And
  • Or
  • Xor
  • Not

Bitwise simply means that the operations can be performed on two binary numbers bit by bit. Microsoft uses truth tables to document bitwise operations. The truth table for And is:

1st Bit   2nd Bit   Result

    1      1      1

    1      0      0

    0      1      0

    0      0      0

In my school, they taught Karnaugh maps instead. The Karnaugh map for all four operations are shown in the illustration below.

Click Here to display the illustration
Click the Back button on your browser to return

Here's a simple example using the And operation with two, four bit binary numbers:

The result of 1100 And 1010 is 1000.

That's because 1 And 1 is 1 (the first bit) and the rest are 0.

To begin with, let's take a look at the bit operations that are directly supported in VB.NET: bit shifting.

Although both left shift and right shift are available, they work the same way so only left shift will be discussed. Bit shifting is most often used in cryptography, image processing and communications.

VB.NET's bit shifting operations ...

  • Only work with the four types of integers: Byte, Short, Integer, and Long
  • Are arithmetic shifting operations. That means that bits shifted past the end of the result are thrown away, and the bit positions opened up on the other end are set to zero. The alternative is called circular bit shifting and the bits shifted past one end are simply added to the other. VB.NET doesn't support circular bit shifting directly. If you need it, you'll have to code it the old fashioned way: multiplying or dividing by 2.
  • Never generate an overflow exception. VB.NET takes care of any possible problems and I'll show you what that means. As noted, you can code your own bit shifting by multiplying or dividing by 2, but if you use the "code your own" approach, you have to test for overflow exceptions that can cause your program to crash.

A standard bit shifting operation would look something like this:

Dim StartingValue As Integer = 14913080
Dim ValueAfterShifting As Integer
ValueAfterShifting = StartingValue << 50

In words, this operation takes the binary value 0000 0000 1110 0011 1000 1110 0011 1000 (14913080 is the equivalent decimal value - notice that it's just a series of 3 0's and 3 1's repeated a few times) and shifts it 50 places left. But since an Integer is only 32 bits long, shifting it 50 places is meaningless.

VB.NET solves this problem by masking the shift count with a standard value that matches the data type being used. In this case, ValueAfterShifting is an Integer so the maximum that can be shifted is 32 bits. The standard mask value that works is 31 decimal or 11111.

Masking means that the value, in this case 50, is Anded with the mask. This gives the maximum number of bits that can actually be shifted for that data type.

In decimal:

50 And 31 is 18 - The maximum number of bits that can be shifted

It actually makes more sense in binary. The high order bits that can't be used for the shifting operation are simply stripped away.

110010 And 11111 is 10010

When the code snippet is executed, the result is 954204160 or, in binary, 0011 1000 1110 0000 0000 0000 0000 0000. The 18 bits on the left side of the first binary number are shifted off and the 14 bits on the right side are shifted left.

The other big problem with shifting bits is what happens when the number of places to shift is a negative number. Let's use -50 as the number of bits to shift and see what happens.

ValueAfterShifting = StartingValue << -50

When this code snippet is executed, we get -477233152 or 1110 0011 1000 1110 0000 0000 0000 0000 in binary. The number has been shifted 14 places left. Why 14? VB.NET assumes that the number of places is an unsigned integer and does an And operation with the same mask (31 for Integers).

1111 1111 1111 1111 1111 1111 1100 1110
0000 0000 0000 0000 0000 0000 0001 1111
0000 0000 0000 0000 0000 0000 0000 1110

1110 in binary is 14 decimal. Notice that this is the reverse of shifting a positive 50 places.

On the next page, we move on to some other bit operations, starting with Xor Encryption!

I mentioned that one use of bit operations is encryption. Xor encryption is a popular and simple way to "encrypt" a file. In my article, Very Simple Encryption using VB.NET, I show you a better way using string manipulation instead. But Xor encryption is so common that it deserves to at least be explained.

Encrypting a text string means translating it into another text string that doesn't have an obvious relationship to the first one.

You also need a way to decrypt it again. Xor encryption translates the binary ASCII code for each character in the string into another character using the Xor operation. In order to do this translation, you need another number to use in the Xor. This second number is called the key.

Xor encryption is called a "symmetric algorithm". This means that we can use the encryption key as the decryption key too.

Let's use "A" as the key and encrypt the word "Basic". The ASCII code for "A" is:

0100 0001 (decimal 65)

The ASCII code for Basic is:

B - 0100 0010
a - 0110 0001
s - 0111 0011
i - 0110 1001
c - 0110 0011

The Xor of each of these is:

0000 0011 - decimal 3
0010 0000 - decimal 32
0011 0010 - decimal 50
0010 1000 - decimal 40
0010 0010 - decimal 34

This little routine does the trick:

-- Xor Encryption --

Dim i As Short
ResultString.Text = ""
Dim KeyChar As Integer
KeyChar = Asc(EncryptionKey.Text)
For i = 1 To Len(InputString.Text)
   ResultString.Text &= _
      Chr(KeyChar Xor _
      Asc(Mid(InputString.Text, i, 1)))

The result can be seen in this illustration:

Click Here to display the illustration
Click the Back button on your browser to return

To reverse the encryption, just copy and paste the string from the Result TextBox back into the String TextBox and click the button again.

Another example of something you can do with bitwise operators is to swap two Integers without declaring a third variable for temporary storage.

This is the kind of thing they used to do in assembly language programs years ago. It's not too useful now, but you might win a bet someday if you can find someone who doesn't believe you can do it. In any case, if you still have questions about how Xor works, working through this should put them to rest. Here's the code:

Dim FirstInt As Integer
Dim SecondInt As Integer
FirstInt = CInt(FirstIntBox.Text)
SecondInt = CInt(SecondIntBox.Text)
FirstInt = FirstInt Xor SecondInt
SecondInt = FirstInt Xor SecondInt
FirstInt = FirstInt Xor SecondInt
ResultBox.Text = "First Integer: " & _
   FirstInt.ToString & " - " & _
   "Second Integer: " & _

And here's the code in action:

Click Here to display the illustration
Click the Back button on your browser to return

Figuring out exactly why this works will be left as "as an exercise for the student".

On the next page, we reach the goal: General Bit Manipulation

Although these tricks are fun and educational, they're still no substitute for general bit manipulation. If you really get down to the level of bits, what you want is a way to examine individual bits, set them, or change them. That's the real code that is missing from .NET.

Perhaps the reason it's missing is that it's not that hard to write subroutines that accomplish the same thing.

A typical reason you might want to do this is to maintain what is sometimes called a flag byte.

Some applications, especially those written in low level languages like assembler, will maintain eight boolean flags in a single byte. For example, a 6502 processor chip's status register holds this information in a single 8 bit byte:

Bit 7. Negative flag
Bit 6. Overflow flag
Bit 5. Unused
Bit 4. Break flag
Bit 3. Decimal flag
Bit 2. Interrupt-disable flag
Bit 1. Zero flag
Bit 0. Carry flag

(from Wikipedia)

If your code has to work with this kind of data, you need general purpose bit manipulation code. This code will do the job!

' The ClearBit Sub clears the 1 based, nth bit
' (MyBit) of an integer (MyByte).
Sub ClearBit(ByRef MyByte, ByVal MyBit)
   Dim BitMask As Int16
   ' Create a bitmask with the 2 to the nth power bit set:
   BitMask = 2 ^ (MyBit - 1)
   ' Clear the nth Bit:
   MyByte = MyByte And Not BitMask
End Sub

' The ExamineBit function will return True or False
' depending on the value of the 1 based, nth bit (MyBit)
' of an integer (MyByte).
Function ExamineBit(ByVal MyByte, ByVal MyBit) As Boolean
   Dim BitMask As Int16
   BitMask = 2 ^ (MyBit - 1)
   ExamineBit = ((MyByte And BitMask) > 0)
End Function

' The SetBit Sub will set the 1 based, nth bit
' (MyBit) of an integer (MyByte).
Sub SetBit(ByRef MyByte, ByVal MyBit)
   Dim BitMask As Int16
   BitMask = 2 ^ (MyBit - 1)
   MyByte = MyByte Or BitMask
End Sub

' The ToggleBit Sub will change the state
' of the 1 based, nth bit (MyBit)
' of an integer (MyByte).
Sub ToggleBit(ByRef MyByte, ByVal MyBit)
   Dim BitMask As Int16
   BitMask = 2 ^ (MyBit - 1)
   MyByte = MyByte Xor BitMask
End Sub

To demonstrate the code, this routine calls it (parameters not coded on Click Sub):

Private Sub ExBitCode_Click( ...
   Dim Byte1, Byte2 As Byte
   Dim MyByte, MyBit
   Dim StatusOfBit As Boolean
   Dim SelectedRB As String
   StatusLine.Text = ""
   SelectedRB = GetCheckedRadioButton(Me).Name
   Byte1 = ByteNum.Text ' Number to be converted into Bit Flags
   Byte2 = BitNum.Text ' Bit to be toggled
   ' The following clears the high-order byte & returns only the
   ' low order byte:
   MyByte = Byte1 And &HFF
   MyBit = Byte2
   Select Case SelectedRB
      Case "ClearBitButton"
         ClearBit(MyByte, MyBit)
         StatusLine.Text = "New Byte: " & MyByte
      Case "ExamineBitButton"
         StatusOfBit = ExamineBit(MyByte, MyBit)
         StatusLine.Text = "Bit " & MyBit & _
            " is " & StatusOfBit
      Case "SetBitButton"
         SetBit(MyByte, MyBit)
         StatusLine.Text = "New Byte: " & MyByte
      Case "ToggleBitButton"
         ToggleBit(MyByte, MyBit)
         StatusLine.Text = "New Byte: " & MyByte
   End Select
End Sub
Private Function GetCheckedRadioButton( _
   ByVal Parent As Control) _
   As RadioButton
   Dim FormControl As Control
   Dim RB As RadioButton
   For Each FormControl In Parent.Controls
      If FormControl.GetType() Is GetType(RadioButton) Then
         RB = DirectCast(FormControl, RadioButton)
         If RB.Checked Then Return RB
      End If
   Return Nothing
End Function

The code in action looks like this:

Click Here to display the illustration
Click the Back button on your browser to return