1Learning Outcomes¶
Understand how bitwise operations “flip” or “keep” bits from operands.
Identify use cases for AND, OR, XOR, and NOT.
🎥 Walkthrough Video
Please access this YouTube video using UC Berkeley login.
Our sincerest thanks for this video recording go to Adelson Chua, one of our Fall 2022 CS 61C course staff members.
So far, we have learned about arithmetic operations involving binary numbers. In this section, we will learn about bitwise operations.
2Bitwise Operations¶
We denote the bitwise operations AND, OR, XOR, and NOT as the operators &, |, ^, and ~, respectively. Supposing a and b are single-bit values, the following truth tables specify the result y of each operation.[1]
Table 1 is bitwise AND. a & b is 1 only if both a and b are 1. Otherwise, it is 0.
Table 1:AND: y = a & b
a | b | y |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Table 2 is bitwise OR. a | b is 1 only if either a or b are 1. Otherwise, it is 0.
Table 2:OR: y = a | b
a | b | y |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
Table 3 is bitwise NOT. It is a unary operator because it only takes one operand. ~a is 1 only if a is 0. If a is 1, then ~a is 0.
Table 3:NOT: y = ~a
a | y |
|---|---|
| 0 | 1 |
| 1 | 0 |
Table 4 is bitwise XOR (“exclusive OR”). a ^ b is 1 only if one of a and b is 1. Otherwise if both a and b are 0 or 1, a^b is 0.
Table 4:XOR: y = a ^ b
a | b | y |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
2.1Properties of Bitwise Operations¶
The below properties in Table 5 hold for a single-bit value x. We leave the proofs to you.
Table 5:Properties of bitwise operations AND, OR, and XOR.
| Bitwise Operation | Example | Result | Colloquially |
|---|---|---|---|
| AND | x & 0 | 0 | set to 0 |
| AND | x & 1 | x | keep/pass-through |
| OR | x & 0 | x | keep/pass-through |
| OR | x & 1 | 1 | set to 1 |
| XOR | x & 0 | ~x | flip/invert |
| XOR | x & 1 | x | keep/pass-through |
Because of its behavior, we also call XOR a “conditional inverter”. We discuss this more when we design logic gates.
3C: Bitwise Operations vs. Logical Operations¶
The bitwise operators &, |, and ~ are used in C. With n-bit operands, bitwise operations are performed on the binary numeral(s) one bit at a time; the result’s bitwidth depends on the input operands. See Table 6 for examples on 8-bit char values.
Table 6:Bitwise operation examples with 8-bit char values.
| Bitwise Operation | C example | Result |
|---|---|---|
| AND | 0b00001001 & 0b00000011 | 0b00000001 |
| OR | 0b00001001 | 0b00000011 | 0b00001011 |
| XOR | 0b00001001 ^ 0b00000011 | 0b00001010 |
| NOT | ~0b00001001 | 0b11110110 |
However, note that C bitwise operators should not be confused with the C logical operators &&, ||, and !. By contrast, Logical operations translate bit values to truthy and and falsy values. These types of operations are also known as boolean compound operators[2].
4Bitmasks¶
This is our first foray into bitwise operations. Why do we care?
Remember that n bits can represent things, and we often want to use bits to represent many more things than just numbers. Suppose we wanted to use bit patterns to represent whether n things were present. We could then use each of our n bits to represent whether each thing was present (1) or not 0.
Using bitwise operations (and the properties of such bitwise operations) will be very convenient for updating state using bit patterns called bitmasks.
Bitwise operations will be very useful for boolean logic later on when we introduce logic gates.
5More C Bitwise Operators: Left and Right Shift¶
Two additional operations describe bit shifts. We will revisit bit shifting operations later in the course. For now, we define them for the sake of being comprehensive.
Suppose you have the 8-bit bit patterns (where we put spaces between nibbles for readability):
x, with bit pattern0001 0001y, with bit pattern1111 0001
Left shift x << n shifts the bits of x left, filling the lower bits coming in from the left with 0’s. Mathematically, this is equivalent to multiplying x by . For example, x << 3 gives the bit pattern 0000 1000, where the leftmost 1 gets “shifted out.”
Right shift, x >> n shifts the bits of x right. Mathematically, this is equivalent to taking the floor of a division by $2^{\texttt{n}}4 We will still need to fill in the top bits coming in from the right somehow, but the precise operation in C depends on x’s type.
Logical right shift “zero-extends” and fills the top bits with
0. Ifxis an unsigned 8-bit integer, thenx >> 2gives the bit pattern0000 0100, where the rightmost1gets shifted out. This is equivalent to(unsigned char) 17 >> 2yielding4.Arithmetic right shift “sign-extends” and fills the top bits with the sign bit of
x. Arithmetic right shift therefore preserves the sign bit of the result when using signed operands.
Show answer
Logically, left-shifting shifts a bit pattern left and inserts zeros. Arithmetically, left-shifting a number (regardless of its sign) multiplies it by a power of two, which also inserts zeros. Arithmetic and logical left shifts are therefore equivalent.