Sunday, November 24, 2019
Bitwise Operations in VB.NET
Bitwise Operations in VB.NET VB.NET doesnt 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 illustrationClick the Back button on your browser to return Heres a simple example using the And operation with two, four bit binary numbers: The result of 1100 And 1010 is 1000. Thats because 1 And 1 is 1 (the first bit) and the rest are 0. To begin with, lets 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.NETs 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 doesnt support circular bit shifting directly. If you need it, youll 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 Ill 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 14913080Dim ValueAfterShifting As IntegerValueAfterShifting 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 its just a series of 3 0s and 3 1s 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 cant 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. Lets 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 11100000 0000 0000 0000 0000 0000 0001 1111(And)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 doesnt 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. Lets 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 0010a - 0110 0001s - 0111 0011i - 0110 1001c - 0110 0011 The Xor of each of these is: 0000 0011 - decimal 30010 0000 - decimal 320011 0010 - decimal 500010 1000 - decimal 400010 0010 - decimal 34 This little routine does the trick: Xor Encryption Dim i As ShortResultString.Text Dim KeyChar As IntegerKeyChar Asc(EncryptionKey.Text)For i 1 To Len(InputString.Text)à à à ResultString.Text _à à à à à à Chr(KeyChar Xor _à à à à à à Asc(Mid(InputString.Text, i, 1)))Next The result can be seen in this illustration: Click Here to display the illustrationClick 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. Its not too useful now, but you might win a bet someday if you can find someone who doesnt 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. Heres the code: Dim FirstInt As IntegerDim SecondInt As IntegerFirstInt CInt(FirstIntBox.Text)SecondInt CInt(SecondIntBox.Text)FirstInt FirstInt Xor SecondIntSecondInt FirstInt Xor SecondIntFirstInt FirstInt Xor SecondIntResultBox.Text First Integer: _à à à FirstInt.ToString - _à à à Second Integer: _à à à SecondInt.ToString And heres the code in action: Click Here to display the illustrationClick 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, theyre 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. Thats the real code that is missing from .NET. Perhaps the reason its missing is that its 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 chips status register holds this information in a single 8 bit byte: Bit 7. Negative flagBit 6. Overflow flagBit 5. UnusedBit 4. Break flagBit 3. Decimal flagBit 2. Interrupt-disable flagBit 1. Zero flagBit 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 BitMaskEnd 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 BitMaskEnd Sub The ToggleBit Sub will change the state of the 1 based, nth bit (MyBit) of an integer (MyByte).Sub ToggleBit(ByRef MyByte, ByV al MyBit)à à à Dim BitMask As Int16à à à BitMask 2 ^ (MyBit - 1)à à à MyByte MyByte Xor BitMaskEnd 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 SelectEnd SubPrivate 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à à à Nextà à à Return NothingEnd Function The code in action looks like this: Click Here to display the illustrationClick the Back button on your browser to return
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.