Back

Bitwise manipulation and masks (AND OR XOR)

Introduction
Bitwise operations are similar to Boolean logic operations except that they work on individual bits in a byte rather than on whole codes or characters. In this section, we are going to look at the commonest operators and how they are typically used.

What bitwise operators are available?

Operator Symbol used Description
AND & The AND operator compares 2 bits. If they are both 1, then the result is 1, otherwise the result is 0.
OR | The OR operator compares 2 bits. If either of them is a 1, or both of them is a 1, then the result is 1, otherwise the result is 0.
EXCLUSIVE OR (XOR) ^ The EXCLUSIVE OR operator compares 2 bits. If either of them is a 1, the result is 1. If they are both 0 or both 1, then the result is 0. (Both bits must be different for the result to be a 1.)
COMPLEMENT ~ The COMPLEMENT operand simply inverts all the bits so all the ones become zeros and all the zeros become ones.
SHIFT RIGHT >> The SHIFT RIGHT operator shifts all the bits to the right by one position. The bit that was originally on the right is discarded. The new bit that appears on the left is set to 0. Each SHIFT RIGHT is the equivalent of dividing by 2.
SHIFT LEFT << The SHIFT LEFT operator shifts all the bits to the left by one position. The bit that was originally on the left is discarded. The new bit that appears on the right is set to 0. Each SHIFT LEFT is the equivalent of multiplying by 2.

Uses for bitwise operators, including clearing registers
Bitwise operators have a number of uses. One of the most important is to check the status of 'flags'. A flag is simply an indicator of whether something is TRUE or FALSE or is used to indicate whether something has happened or not. Consider a single byte 0000 0000. This byte has 8 bits. Each of those bits could be used as a flag. For example, suppose the computer regularly checks the status of 8 pieces of hardware in turn. Each piece of hardware can be assigned a particular bit in this byte. If the hardware is functioning correctly, the relavant bit is made a 0 (we talk about 'resetting' a bit when we make it 0). If there is a fault, however, the flag for that piece of hardware is set to 1. We can use bitwise operators to set and reset bits, and we can use bitwise operators to go through and check each bit in turn later on, to see what value it is. We will see examples of this later using 'masks' to test if a bit has changed.

We can use bitwise operators to perform some Maths tasks, as SHIFT RIGHT has the effect on a number of dividing it by 2. SHIFT LEFT has the effect of multiplying it by 2. The shifting of bits is also important in some areas of software development. For example, it is used in the algorithm known as MD5, which is used to verify that a file has not been corrupted. Manipulating bits is a very important area for Assembly programmers, as they work on a register level. A typical Assembly operation might involve doing some Maths on two numbers. Each time any calculation is done, individual flags held in special registers are set to indicate whether there was a remainder, whether the result was negative, whether the result was invalid and produced an overflow or underflow (because the result couldn't be stored in the size of variable assigned to hold the result) and so on. We can then test these flags in turn, and do different piece of code, depending on whether there was a remainder, an invalid result and so on.

Another use of bitwise operators is to quickly clear out a register. This can easily be achieved by ANDing a 16-bit register with 0000 0000 0000 0000, for example.

AND bitwise operator - both bits must be a 1 for the result to be a 1, otherwise the result is a 0.

Example 1   01011100 & 11001110

7 6 5 4 3 2 1 0 Bit position
0 1 0 1 1 1 0 0 Data 1
1 1 0 0 1 1 1 0 Data 2
0 1 0 0 1 1 0 0 AND result

Example 2  00101010 & 11101100

7 6 5 4 3 2 1 0 Bit position
0 0 1 0 1 0 1 0 Data 1
1 1 1 0 1 1 0 0 Data 2
0 0 1 0 1 0 0 0 AND result

 

OR bitwise operator - Either bit must be a 1, or both bits must be a 1, for the result to be a 1, otherwise the result is a 0.

Example 3   10001000 | 11000001

7 6 5 4 3 2 1 0 Bit position
1 0 0 0 1 0 0 0 Data 1
1 1 0 0 0 0 0 1 Data 2
1 1 0 0 1 0 0 1 OR result

Example 4  00010011 | 00000001

7 6 5 4 3 2 1 0 Bit position
0 0 0 1 0 0 1 1 Operator 1
0 0 0 0 0 0 0 1 Operator 2
0 0 0 1 0 0 1 1 OR result

 

XOR bitwise operator - both bits must be different for the result to be a 1, otherwise the result is a 0.

Example 5   10011110 ^ 00010001

7 6 5 4 3 2 1 0 Bit position
1 0 0 1 1 1 1 0 Data 1
0 0 0 1 0 0 0 1 Data 2
1 0 0 0 1 1 1 1 XOR result

Example 6  00001010 ^ 11001100

7 6 5 4 3 2 1 0 Bit position
0 0 0 0 1 0 1 0 Data 1
1 1 0 0 1 1 0 0 Data 2
1 1 0 0 0 1 1 0 XOR result

 

Complement bitwise operator - invert the bits!

Example 7  ~ 01111100

7 6 5 4 3 2 1 0 Bit position
0 1 1 1 1 1 0 0 Data
1 0 0 0 0 0 1 1 COMPLEMENT result

Example 8  ~ 10100010

1 0 1 0 0 0 1 0 Data
0 1 0 1 1 1 0 1 COMPLEMENT result

 

SHIFT RIGHT bitwise operator - shift all the bits one place to the right. Discard the original LSB and replace the MSB with a 0.

Example 9   >> 10100011

7 6 5 4 3 2 1 0 Bit position
1 0 1 0 0 0 1 1 Data
0 1 0 1 0 0 0 1 SHIFT RIGHT result

Example 10  >> 10011000

7 6 5 4 3 2 1 0 Bit position
1 0 0 1 1 0 0 0 Data
0 1 0 0 1 1 0 0 SHIFT RIGHT result

 

LEFT SHIFT bitwise operator - shift all the bits one place to the left. Discard the original MSB and replace the LSB with a 0.

Example 11   << 11000001

7 6 5 4 3 2 1 0 Bit position
1 1 0 0 0 0 0 1 Data
1 0 0 0 0 0 1 0 SHIFT LEFT result

Example 12  << 00101010

7 6 5 4 3 2 1 0 Bit position
0 0 1 0 1 0 1 0 Data
0 1 0 1 0 1 0 0 SHIFT LEFT result

 

Using masks to change bits and test bits
A mask is a bit pattern that has been defined by a programmer, which allows specific bits in a piece of data to be tested or altered.

Setting bits to 1
If you need to turn on a specific bit, you can do this using the OR bitwise operation and a suitable mask. For example, if you need to turn on Bit 4 and Bit 7 of a byte (remember that the bit on the right hand side is Bit 0), you can use the mask 1001 0000 and the OR bitwise operation.

7 6 5 4 3 2 1 0 Bit position
0 0 0 0 0 0 0 0 Data
1 0 0 1 0 0 0 0 Mask
1 0 0 1 0 0 0 0  OR Result

Resetting bits to 0
You can't force a bit to be 0 using the OR command. You can use the bitwise command AND along with a suitable mask, however. For example, suppose you wanted to reset Bits 0, 1 and 2 in a byte but leave all the other bits as they were. You would use the mask 1111 1000 along with the AND bitwise operator.

7 6 5 4 3 2 1 0 Bit position
1 0 1 0 1 0 1 1 Data
1 1 1 1 1 0 0 0 Mask
1 0 1 0 1 0 0 0  AND Result

Checking a specific bit
You can easily test what a bit is using the AND bitwise operator and a suitable mask. For example, suppose you wanted to test Bit 2 of a piece of data to see if it was a 0 or 1. You would turn off all the other bits using the AND bitwise operator, but test Bit 2 by ANDing it with 1. The mask you would use in this case is 0000 0100 and here is an example of how it works. In the first example, Bit 2 of the data we want to test is a zero and ANDing it with 1 results in a 0.

7 6 5 4 3 2 1 0 Bit position
0 1 1 0 1 0 0 0 Data
0 0 0 0 0 1 0 0 Mask
0 0 0 0 0 0 0 0  AND Result

We can test the result now. If the result is a zero as it is in this case, then Bit 2 in our data was a 0. 

Now see what happens if Bit 2 in the previous data was actually a 1 to start with. When you AND a 1 with a 1, the result is a 1.

7 6 5 4 3 2 1 0 Bit position
0 1 1 0 1 1 0 0 Data
0 0 0 0 0 1 0 0 Mask
0 0 0 0 0 1 0 0  AND Result

As you can see, the result is now not zero anymore. In this situation, it tells us that Bit 0 in the original piece of data must have been a 1 to start with.

Testing bits like this is very important. Based on the result of the test, we can branch off and do different things in a program.

Toggling bits (making a 1 bit into a 0 and making a 0 bit into a 1).
We have seen how to turn bits on, and how to turn them off but we haven't seen how to do this at the same time. For this, we need the XOR bitwise operator. Suppose we want to toggle bits 4, 5, 6 and 7 but leave Bits 0, 1, 2 and 3 in whatever state they are in. The mask we would need is 1111 0000 along with the XOR operator. 

7 6 5 4 3 2 1 0 Bit position
1 0 1 0 1 0 1 0 Data
1 1 1 1 0 0 0 0 Mask
0 1 0 1 1 0 1 0  XOR Result

As you can see, the bits that we didn't want to toggle stayed as they were. However the bits that we did want to toggle were indeed flipped over to the opposite state.

An example of using bitwise operators to control how some text will be displayed
Let us assume that we are going to control how some text will be displayed. We are going to define and use a single byte variable called textVar to do this. We will define each bit in the byte as follows:

BOLD ITALIC UNDERLINE BLINKING STRIKE THROUGH NOT USED NOT USED NOT USED ATTRIBUTE
7 6 5 4 3 2 1 0 BIT POSITION
128 64 32 16 8 4 2 1 VALUE

Just to remind you, a byte has typically 8 bits. The bit on the left has the biggest value and is worth 128. It is called the Most Significant Bit (MSB) and its position in the byte is Bit 7 (because in computing, we start counting from 0). The bit on the right is the Least Significant Bit (LSB) is Bit 0 and is worth 1. When you work with bits, you need to be very clear the number of the bit you are talking about, its value and terms like MSB and LSB.

To make the text bold, we could use this instruction:

textVar = 128

because 128 is the bit pattern 1000 0000. This turns the Bold attribute on and makes the text bold.

Now we can turn the Underline attribute on as well, like this:

textVar = 128 | 32

This will do the bitwise operation 1000 0000 OR 0010 0000 which results in textVar being given the value 1010 0000 and both the bold and underline attributes are switched on.

We could switch off the Bold attribute now. Let's use XOR, like this:

textVar = textVar ^ 128

This takes what was in textVar and XORs it with 1000 0000. In other words, it does 1010 0000 XOR 1000 0000 and this results in 0010 0000, which switches the bold attribute off but keeps the underline one on.

Back