Bitwise operators


1.1.   Bitwise operators

The bitwise operators treat their operands as a series of individual bits rather than a numerical value. They work only with integer variables or integer constants as operands, so only data types  short , int , long , long long , signed char , and char , as well as the unsigned variants of these,can be used. The bitwise operators are useful in programming hardware devices, where the status of a device is often represented as a series of individual fl ags (that is, each bit of a byte may signify the status of a different aspect of the device), or for any situation where you might want to pack a set of on - off fl ags into a single variable. You will see them in action when you look at input/output in detail, where single bits are used to control various options in the way data is handled.
There are six bitwise operators:
& bitwise AND
| bitwise OR
^ bitwise exclusive OR
~ bitwise NOT
> > shift right
> > shift right

The following sections take a look at how each of them works.

1.1.1.                 The Bitwise AND

The bitwise AND, & , is a binary operator that combines corresponding bits in its operands in a particular way. If both corresponding bits are 1, the result is a 1 bit, and if either or both bits are 0, the result is a 0 bit. The effect of a particular binary operator is often shown using what is called a truth table . This shows, for various possible combinations of operands, what the result is. The truth table for & is as follows:
Bitwise AND
0
1
0
0
0
1
0
1

For each row and column combination, the result of & combining the two is the entry at the intersection of the row and column. You can see how this works in an example:
char letter1 = 'A', letter2 = 'Z', result = 0;
result = letter1 & letter2;
You need to look at the bit patterns to see what happens. The letters ‘ A ’ and ‘ Z ’ correspond to hexadecimal values 0x41 and 0x5A, respectively. You can confirm this by looking at how corresponding bits combine with & in the truth table. After the assignment, result will have the value 0x40, which corresponds to the character " @ ". Because the & produces zero if either bit is zero, you can use this operator to make sure that unwanted bits are set to 0 in a variable. You achieve this by creating what is called a “mask” and combining with the original variable using & . You create the mask by specifying a value that has 1 where you want to keep a bit, and 0 where you want to set a bit to zero. The result of AND - ing the mask with another integer will be 0 bits where the mask bit is 0, and the same value as the original bit in the variable where the mask bit is 1. Suppose you have a variable letter of type char where, for the purposes of illustration, you want to eliminate the high - order 4 bits, but keep the low – order 4 bits. This is easily done by setting up a mask as 0x0F and combining it with the value of letter using & like this:
letter = letter & 0x0F;
or, more concisely:
letter & = 0x0F;
If letter started out as 0x41 , it would end up as 0x01 as a result of either of these statements.  The 0 bits in the mask cause corresponding bits in letter to be set to 0, and the 1 bits in the mask cause corresponding bits in letter to be kept as they are. Similarly, you can use a mask of 0xF0 to keep the 4 high - order bits, and zero the 4 low - order bits. Therefore, this statement,
letter & = 0xF0;
will result in the value of letter being changed from 0x41 to 0x40 .

1.1.2.                 The Bitwise OR

The bitwise OR, | , sometimes called the inclusive OR , combines corresponding bits such that the result is a 1 if either operand bit is a 1, and 0 if both operand bits are 0. The truth table for the bitwise OR is:

Bitwise OR
0
1
0
0
1
1
1
0
You can exercise this with an example of how you could set individual flags packed into a variable of type int. Suppose that you have a variable called style of type short that contains 16 individual 1 - bitflags. Suppose further that you are interested in setting individual flags in the variable style. One way of doing this is by defining values that you can combine with the OR operator to set particular bits on. To use in setting the rightmost bit, you can define:
short vredraw = 0x01;
For use in setting the second - to - rightmost bit, you could define the variable hredraw as:
short hredraw = 0x02;
So, you could set the rightmost two bits in the variable style to 1 with the statement:
style = hredraw | vredraw;
Of course, to set the third bit of style to 1, you would use the constant 0x04. Because the OR operation results in 1 if either of two bits is a 1, OR - ing the two variables together produces a result with both bits set on. may have been set elsewhere. You can do this quite easily with a statement such as:
style |= hredraw | vredraw;
This statement will set the two rightmost bits of the variable style to 1, leaving the others at whatever they were before the execution of this statement.

1.1.3.                 The Bitwise Exclusive OR

The exclusive OR, ^ , is so called because it operates similarly to the inclusive OR but produces 0 when both operand bits are 1. Therefore, its truth table is as follows:
Bitwise EOR
0
1
0
0
1
1
1
0
Using the same variable values that we used with the AND, you can look at the result of the following statement:
result = letter1 ^ letter2;
This operation can be represented as:
letter1 0100 0001
letter2 0101 1010
EOR - ed together produce:
result 0001 1011
The variable result is set to 0x1B , or 27 in decimal notation. The ^ operator has a rather surprising property. Suppose that you have two char variables, first with the value ‘ A ’ , and last with the value ‘ Z ’ , corresponding to binary values 0100 0001 and 0101 1010. If you write the statements,
first ^= last; // Result first is 0001 1011
last ^= first; // Result last is 0100 0001
first ^= last; // Result first is 0101 1010
the result of these is that first and last have exchanged values without using any intermediate memory location. This works with any integer values.

1.1.4.                 The Bitwise NOT

The bitwise NOT, ~ , takes a single operand, for which it inverts the bits: 1 becomes 0, and 0 becomes 1. Thus, if you execute the statement,
result = ~letter1;
if letter1 is 0100 0001, the variable result will have the value 1011 1110, which is 0xBE, or 190 as a decimal value.

1.1.5.                 The Bitwise Shift Operators

These operators shift the value of an integer variable a specified number of bits to the left or right. The operator > > is for shifts to the right, while < < is the operator for shifts to the left. Bits that “fall off ” either end of the variable are lost.
You declare and initialize a variable called number with the statement:
unsigned short number = 16387U;
As you saw earlier in this chapter, you write unsigned integer literals with a letter U or u appended to the number. You can shift the contents of this variable to the left with the statement:
number < < = 2; // Shift left two bit positions
The left operand of the shift operator is the value to be shifted, and the number of bit positions that the value is to be shifted is specified by the right operand. The illustration shows the effect of the operation. As you can see, shifting the value 16,387 two positions to the left produces the value 12.The rather drastic change in the value is the result of losing the high - order bit when it is shifted out. You can also shift the value to the right. Let’s reset the value of number to its initial value of 16,387. Then you can write:
number > > = 2; // Shift right two bit positions
This shifts the value 16,387 two positions to the right, storing the value 4,096. Shifting right 2 bits is effectively dividing the value by 4 (without remainder). This is also shown in the illustration. As long as bits are not lost, shifting n bits to the left is equivalent to multiplying the value by 2, n times. In other words, it is equivalent to multiplying by 2 n. Similarly, shifting right n bits is equivalent to dividing by 2 n. But beware: as you saw with the left shift of the variable number, if significant bits are lost, the result is nothing like what you would expect. However, this is no different from the multiply operation. If you multiplied the 2 - byte number by 4, you would get the same result, so shifting left and multiply are still equivalent. The problem of accuracy arises because the value of the result of the multiplication is outside the range of a 2 - byte integer. You might imagine that confusion could arise between the operators that you have been using for input and output and the shift operators. As far as the compiler is concerned, the meaning will always be clear from the context. If it isn ’ t, the compiler will generate a message, but you need to be careful. For example, if you want to output the result of shifting a variable number left by 2 bits, you could write the following statement:
cout < < (number < < 2);
Here, the parentheses are essential. Without them, the shift operator will be interpreted by the compiler as a stream operator, so you won’t get the result that you intended; the output will be the value of number followed by the value 2. The right - shift operation is similar to the left - shift. For example, suppose the variable number has the value 24, and you execute the following statement:
number > > = 2;
This will result in number having the value 6, effectively dividing the original value by 4. However, the right shift operates in a special way with signed integer types that are negative (that is, the sign bit, which is the leftmost bit, is 1). In this case, the sign bit is propagated to the right. For example, declare and initialize a variable number of type char with the value  104 in decimal:
char number = -104; // Binary representation is 1001 1000
Now you can shift it right 2 bits with the operation:
number > > = 2; // Result 1110 0110
The decimal value of the result is  26, as the sign bit is repeated. With operations on unsigned integer types, of course, the sign bit is not repeated and zeros appear.
You may be wondering how the shift operators, < < and > > , can be the same as the operators used with the standard streams for input and output. These operators can have different meanings in the two contexts because cin and cout are stream objects, and because they are objects, it is possible to redefine the meaning of operators in context by a process called operator overloading. Thus, the > > operator has been redefined for input stream objects such as cin , so you can use it in the way you have seen. The < < operator has also been redefi ned for use with output stream objects such as cout. 
Share on Google Plus