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 | keep/pass-through |
| XOR | x ^ 1 | ~x | flip/invert |
Because of its behavior, we also call XOR a “conditional inverter”. We discuss this more when we design logic gates (see later section).
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.
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 by n bits, filling the n lower bits (“coming in from the right”) with 0’s. Mathematically, this is equivalent to multiplying x by .
For example,
x << 2gives the bit pattern0100 0100. If we interpretxas a signed 8-bit integer 17, thenx << 2is indeed .Left shifting also encounters overflow:
x << 4gives the bit pattern0001 0000where the leftmost1gets “shifted out” of the 8-bit type (to produce the signed 8-bit integer 16, which is certainly not ).
Right shift, x >> n shifts the bits of x right by n bits. Mathematically, this is equivalent to taking the floor of a division by . 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 upper 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 upper 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.
6Practice¶
Show answer
B. 0x3400.
Nis0x000034FFN << 0x10is0x34FF 0000. We left shiftNby 16.(N << 0x10) >> 0x8is0x0034 FF00. BecauseNis an unsigned integer, arithmetic right shift by 8 inserts zeros and is equivalent to logical right shift.N & (N << 0x10) >> 0x8is0x0000 3400, as per Figure 1. Note that0x34 & 0x00and0xFF & 0x00are both zero, because AND-ing anything with 0 sets all bits to zero.

Figure 1:Result of N & (N << 0x10) >> 0x8, i.e., 0x000034FF & 0x0034 FF00
The name “truth table” comes from boolean logic itself. We discuss in a later section about logic design, when it is useful to represent signals as “high” or “low”.
In Python, the boolean operators are
and,or, andnot. Python also supports bitwise operators&,|,~, and^.