Bitwise and Bitshift Operators
bitwise operators allow you to manipulate different kinds of data in their binary form. In order to follow this lesson, it is recommended that you know what binary system is and how to convert decimal numbers to binary. The binary system is what the computer actually uses since it represents everything in on or off state. On is represented by 1 and off is represented by 0. Therefore, binary numbers can only be 1’s or 0’s. Binary numbers are also called Base 2 numbers and decimal numbers are Base 10. A bit represents one binary digit. A byte represents 8 bits. The int, for example, uses 32 bit or 4 bytes to store its content. It represents the numbers using 32 digits of 0’s and 1’s. For example, the number 100, when stored in an int variable, is read by the computer like this:
000000000000000000000000000001100100
The decimal number 100 is equivalent to 1100100 in binary. But since it is only 7 digits, we added 29 more digits to the left of it to fill the 32 bits required by int. Note that we read binary numbers from right to left so the beginning digit is actually the last one.
We can then use the bitwise operators to the binary versions of the numbers or data. You don’t have to convert them to binary as the computer automatically sees them as binary numbers. The following shows the bitwise operators you can use.
Operator | Name | Category | Example |
---|---|---|---|
& | Bitwise AND | Binary | x = y & z; |
| | Bitwise OR | Binary | x = y | z; |
^ | Bitwise XOR | Binary | x = y ^ z; |
~ | Bitwise NOT | Unary | x = ~y; |
&= | Bitwise AND Assignment | Binary | x &= y; |
| | Bitwise OR Assignment | Binary | x |= y; |
^= | Bitwise XOR Assignment | Binary | x ^= y; |
Bitwise operators are commonly used in bitwise comparisons of Flags enumerations which you will learn in several advance lessons in this site.
Bitwise AND (&) Operator>
The bitwise AND operator does the AND operation to every bit of the binary representation of a value. When doing an AND operation on two binary numbers, the result is 1 if both binary numbers are 1, and 0 otherwise. The AND operation has the following truth table.
X | Y | X & Y |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
As a demonstration of using the bitwise AND operator, let’s take a look at the following code snippet.
int result = 5 & 3;
Console.WriteLine(result);
1
We used the bitwise AND to the values 5 and 3 and as you can see, it yields the value 1. Let’s take a look at how the computer came up with that result.
5: 00000000000000000000000000000101
3: 00000000000000000000000000000011
------------------------------------
1: 00000000000000000000000000000001
We first convert 5 and 3 to their binary equivalents. Since int has 32-bits, we added leading 0’s to fill the 32 slots. We then use the AND operation to each digit. By looking at the truth table in Figure 2, we came up with the binary representation of the number 1.
The assignment version of the bitwise AND operator is also available.
myNumber &= 5;
The above statement applies the bitwise AND operator to whatever the value of myNumber and to the value of the right operand (in this case 5). The result is then assigned to myNumber.
Bitwise OR (|) Operator
The bitwise OR operator uses the OR operation on every bit of the binary representation of two values. The result of an OR operation is shown in the following truth table.
X | Y | X | Y |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
The OR operation yields 0 only if both operands are 0. If at least one value is 1, then it automatically yields 1. Let’s take a look at an example of using this operator.
int result = 7 | 9;
Console.WriteLine(result);
15
In the binary representation, you can see how the computer yields 15 when we used the bitwise OR operator on the two values.
7: 00000000000000000000000000000111
9: 00000000000000000000000000001001
-----------------------------------
15: 00000000000000000000000000001111
We looked at the truth table in Figure 3 to determine the results of doing the OR operation on each digit of their binary representations. We came up with binary number 1111 which is equivalent to 15.
The assignment version of the bitwise OR operator is also available.
myNumber |= 5;
The above statement applies the bitwise OR operator to whatever the value of myNumber and to the value of the right operand (in this case 5). The result is then assigned to myNumber.
Bitwise XOR (^) Operator
The Bitwise XOR (Exclusive OR) performs XOR operations to each digit of the binary representation of two values. The following is the truth table for the XOR operation.
X Y X ^ Y
1 1 0
1 0 1
0 1 1
0 0 0
Figure 4 – XOR Truth Table
The XOR operation yields 0 if both operands are the same, that is, if both are 0’s or both are 1’s. Otherwise, it yields 1. The following example shows the effect of using the bitwise XOR operator on two values.
int result = 5 ^ 7;
Console.WriteLine(result);
2
The following shows their binary representations and how we arrived at the result value using the bitwise XOR operator.
5: 00000000000000000000000000000101
7: 00000000000000000000000000000111
———————————–
2: 00000000000000000000000000000010
By looking at the XOR truth table and applying the XOR operation on each binary digit pairs, we arrived at the final value which is the binary representation of 2.
The assignment version of the bitwise XOR operator is also available.
myNumber ^= 5;
The above statement applies the bitwise XOR operator to whatever the value of myNumber and to the value of the right operand (in this case 5). The result is then assigned to myNumber.
Bitwise NOT (~) Operator
The bitwise NOT operator performs the NOT operation (inversion) to each binary digit of a number. It is a unary operator so it only needs one operand. The following is the truth table for the NOT operation.
X | ~X |
---|---|
1 | 0 |
0 | 1 |
The NOT operation simply inverts the value of a binary digit. The following shows an example of using the not operator.
int result = ~7;
Console.WriteLine(result);
Let’s look at their binary representations.
7: 00000000000000000000000000000111
------------------------------------
-8: 11111111111111111111111111111000
Inverting every binary digit of 7 results on the binary representation of -8. Binary representations of negative numbers are quite tricky. You need to use the Two’s Complement Notation to the binary form of -8 to see why the computer reads it as -8 (instead of a very big number).
Bitwise Operators Example Usage
To show a practical example of using the bitwise operators, suppose you want to specify a certain style of a font. First, we can give specific numeric codes for each font style.
Style | Code |
---|---|
Regular | 0 |
Bold | 1 |
Italic | 2 |
Underline | 4 |
Strikeout | 8 |
Let’s say the initial value of the font style is 0 which means, the current font style uses regular (or no style).
int fontStyle = 0;
To add the Bold font style, we can use the bitwise OR operator. Note that Bold is represented by code 1.
fontStyle = fontStyle | 1;
To add the Italic font style to the current font style, again, use the bitwise OR operator.
fontStyle |= 2;
Since the font style previously has the value 1 which means bold, adding the italic style 2 will perform bitwise OR operation on 1 and 2 resulting to 3. By looking at the table of styles above, there is no corresponding style for code 3. Therefore, we can assign the 3 to the new style BoldItalic which is a combination of Bold and Italic styles. If we are to add the Underline font style (8) to the current font style (3), the result will be 11, which can represent the font style which is Bold, Italicized, and Underlined at the same time.
Say you want to assign a new style which is a combination of all the styles, then you can simply use the bitwise OR operator between each font style.
fontStyle = 1 | 2 | 4 | 8;
To test if a style is part of the overall font style, we can use the bitwise AND operator.
bool isBold = (fontStyle & 1) == 1;
The expression tests if doing the bitwise AND operation to the current font style yields to the style being tested. If so, the result of the expression is true, otherwise false.
If you want for example to remove the Underline style to the current font style, you can use the bitwise XOR operator.
fontStyle = fontStyle ^ 8;
//or
fontStyle ^= 8;
Once the Underline style is removed, using the bitwise XOR operator again will add the Underline style instead of removing it.
The previous example represented the font styles using plain integers which is hard to read. The proper way is by using enumerations which we will be discussing in an upcoming lesson.
The Bitwise Shift Operators
Another pair of operators called the bitwise shift operators allows you to shift the position of the bits to the left or to the right. Both operators accept two operands, the left being the value whose binary representation will be shifted, and the right operand specifies the number of positions to shift to left or right.
Operator | Name | Category | Example |
---|---|---|---|
<< | Left Shift Operator | Binary | x = y << 2; |
>> | Right Shift Operator | Binary | x = y >> 2; |
<<= | Left Shift Assignment | Binary | x <<= 2; |
>>= | Right Shift Assignment | Binary | x >>= 2; |
Figure 6 – Bitwise Shift Operators
The Left Shift Operator (<<) shifts the bits of the left operand to the left by n positions specified by the right operand. Consider the following example.
int result = 10 << 2;
Console.WriteLine(result);
40
The previous statement indicates that we shift the bits of the decimal value 10, by two positions. Let’s demonstrate the effect by showing their binary representations.
10: 00000000000000000000000000001010
------------------------------------
40: 00000000000000000000000000101000
You can see that every digits were moved by 2 positions. Digits to the left will be discarded and the empty slots to the right where the original bits once reside will be replaced by 0’s. For example, since we shifted 2 positions to the left, the last 2 digits to the left will be dropped, and two 0’s will be added to the right.
Shifting bits to the left has an effect of multiplying the value by 2 multiple times depending on the value of the right operand. For example, the value 10 when shifted to the left by 2 positions multiplies 10 by 2 two times. 10 << 3 will multiply 10 by 2 three times and 10 << 4 will multiply 10 by 2 four times and so on. The number of times a value will be multiplied by 2 depends on the value of the right operand.
The Right Shift Operator (>>) is similar to the left shift operator but it shifts the bits to the right instead of left. The following is an example of using this operator.
int result = 100 >> 4;
Console.WriteLine(result);
6
Using the right shift operator, the bits of value 100 was shifted to the right by 4 positions. Let’s look at their binary equivalents.
100: 00000000000000000000000001100100
------------------------------------
6: 00000000000000000000000000000110
Every bit is moved by 4 positions to the right, so the first 4 bits in the right where dropped and 0’s where added to the right to fill the gap.
Shifting bits to the right has an effect of dividing the value by 2 multiple times depending on the value of the right operand. For example, the value 100 when shifted to the right by 4 positions divides 10 by 2 four times. 100 >> 2 will divide 100 by 2 two times and 100 >> 3will divide 100 by 2 three times and so on. The number of times a value will be divided by 2 depends on the value of the right operand.
The shofthand assignment versions of bitwise operators are also available.
result1 <<= 2;
result2 >>= 4;
They both act the same as the other assignment operators we have seen. Bitwise shift operators are rarely used but it is better to know that these operators exist.