C++ provides extensive bit-manipulation capabilities for getting down to the so-called “bits-and-bytes” level. Operating systems, test-equipment software, networking software and many other kinds of software require that you communicate “directly with the hardware.” We introduce each of the bitwise operators, and we discuss how to save memory by using bit fields.
All data is represented internally by computers as sequences of bits. Each bit can assume the value 0
or the value 1
. On most systems, a sequence of eight bits, each of which forms a byte—the standard storage unit for a variable of type char
. Other data types are stored in larger numbers of bytes. Bitwise operators are used to manipulate the bits of integral operands (char, short, int
and long
; both signed
and unsigned
). Normally the bitwise operators are used with unsigned integers.
Bitwise data manipulations are machine dependent.
The bitwise operator discussions in this section show the binary representations of the integer operands. For a detailed explanation of the binary (also called base-2) number system, see Appendix D. Because of the machine-dependent nature of bitwise manipulations, some of these programs might not work on your system without modification.
The bitwise operators are: bitwise AND (&)
, bitwise inclusive OR (|)
, bitwise exclusive OR (^)
, left shift (<<)
, right shift (>>)
and bitwise complement (~)
—also known as the one’s complement
. We’ve been using &, <<
and >>
for other purposes—this is a classic example of operator overloading. The bitwise AND, bitwise inclusive OR and bitwise exclusive OR operators compare their two operands bit by bit. The bitwise AND operator sets each bit in the result to 1 if the corresponding bit in both operands is 1. The bitwise inclusive OR operator sets each bit in the result to 1 if the corresponding bit in either (or both) operand(s) is 1. The bitwise exclusive OR operator sets each bit in the result to 1 if the corresponding bit in either operand—but not both—is 1. The left-shift operator shifts the bits of its left operand to the left by the number of bits specified in its right operand. The right-shift operator shifts the bits in its left operand to the right by the number of bits specified in its right operand. The bitwise complement operator sets all 0
bits in its operand to 1
in the result and sets all 1
bits in its operand to 0
in the result. Detailed discussions of each bitwise operator appear in the following examples. The bitwise operators are summarized in Fig. 22.5.
Operator | Name | Description |
---|---|---|
& |
bitwise AND | The bits in the result are set to 1 if the corresponding bits in the two operands are both 1 . |
| |
bitwise inclusive OR | The bits in the result are set to 1 if one or both of the corresponding bits in the two operands is 1 . |
^ |
bitwise exclusive OR | The bits in the result are set to 1 if exactly one of the corresponding bits in the two operands is 1 . |
<< |
left shift | Shifts the bits of the first operand left by the number of bits specified by the second operand; fill from right with 0 bits. |
>> |
right shift with sign extension | Shifts the bits of the first operand right by the number of bits specified by the second operand; the method of filling from the left is machine dependent. |
~ |
bitwise complement | All 0 bits are set to 1 and all 1 bits are set to 0 . |
When using the bitwise operators, it’s useful to illustrate their precise effects by printing values in their binary representation. The program of Fig. 22.6 prints an unsigned
integer in its binary representation in groups of eight bits each.
Function displayBits
(lines 18–35) uses the bitwise AND operator to combine variable value
with constant MASK
. Often, the bitwise AND operator is used with an operand called a mask
—an integer value with specific bits set to 1
. Masks are used to hide some bits in a value while selecting other bits. In displayBits
, line 20 initializes constant MASK
with 1 << SHIFT
. The value of constant SHIFT
was calculated in line 19 with the expression
8 * sizeof(unsigned) - 1
which multiplies the number of bytes an unsigned
object requires in memory by 8
(the number of bits in a byte) to get the total number of bits required to store an unsigned
object, then subtracts 1. The bit representation of 1 << SHIFT
on a computer that represents unsigned
objects in four bytes of memory is
10000000 00000000 00000000 00000000
The left-shift operator shifts the value 1
from the low-order (rightmost) bit to the high-order (leftmost) bit in MASK
, and fills in 0
bits from the right. Line 26 prints a 1
or a 0
for the current leftmost bit of variable value
. Assume that variable value
contains 65000
(00000000 00000000 11111101 11101000
). When value
and MASK
are combined using &
, all the bits except the high-order bit in variable value
are “masked off” (hidden), because any bit “ANDed” with 0
yields 0
. If the leftmost bit is 1, value & MASK
evaluates to
00000000 00000000 11111101 11101000 (value)
10000000 00000000 00000000 00000000 (MASK)
-----------------------------------
00000000 00000000 00000000 00000000 (value & MASK)
which is interpreted as false
, and 0
is printed. Then line 27 shifts variable value
left by one bit with the expression value <<= 1
(i.e., value = value << 1
). These steps are repeated for each bit variable value
. Eventually, a bit with a value of 1
is shifted into the leftmost bit position, and the bit manipulation is as follows:
11111101 11101000 00000000 00000000 (value)
10000000 00000000 00000000 00000000 (MASK)
-----------------------------------
10000000 00000000 00000000 00000000 (value & MASK)
Because both left bits are 1
s, the expression’s result is nonzero (true) and 1
is printed. Figure 22.7 summarizes the results of combining two bits with the bitwise AND operator.
&
).Bit 1 | Bit 2 | Bit 1 & Bit 2 |
---|---|---|
0 |
0 |
0 |
1 |
0 |
0 |
0 |
1 |
0 |
1 |
1 |
1 |
Using the logical AND operator (&&
) for the bitwise AND operator (&
) and vice versa is a logic error.
The program of Fig. 22.8 demonstrates the bitwise AND operator, the bitwise inclusive OR operator, the bitwise exclusive OR operator and the bitwise complement operator. Function displayBits
(lines 47–64) prints the unsigned
integer values.
In Fig. 22.8, line 12 uses 2179876355
(10000001 11101110 01000110 00000011
) to initialize variable number1
, and line 14 uses 1
(00000000 00000000 00000000 00000001
) to initialize variable mask
. When mask
and number1
are combined using the bitwise AND operator (&
) in the expression number1 & mask
(line 18), the result is 00000000 00000000 00000000 00000001
. All the bits except the low-order bit in variable number1
are “masked off” (hidden) by “ANDing” with constant MASK
.
The bitwise inclusive OR operator is used to set specific bits to 1 in an operand. In Fig. 22.8, line 21 assigns 15
(00000000 00000000 00000000 00001111
) to variable number1
, and line 22 uses 241
(00000000 00000000 00000000 11110001
) to initialize variable setBits
. When number1
and setBits
are combined using the bitwise inclusive OR operator in the expression number1 | setBits
(line 27), the result is 255
(00000000 00000000 00000000 11111111
). Figure 22.9 summarizes the results of combining two bits with the bitwise inclusive-OR operator.
Using the logical OR operator (||
) for the bitwise OR operator (|
) and vice versa is a logic error.
Bit 1 | Bit 2 | Bit 1 | Bit 2 |
---|---|---|
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
1 |
The bitwise exclusive OR operator (^
) sets each bit in the result to 1 if exactly one of the corresponding bits in its two operands is 1. In Fig. 22.8, lines 30–31 give variables number1
and number2
the values 139
(00000000 00000000 00000000 10001011
) and 199
(00000000 00000000 00000000 11000111
), respectively. When these variables are combined with the bitwise exclusive OR operator in the expression number1 ^ number2
(line 36), the result is 00000000 00000000 00000000 01001100
. Figure 22.10 summarizes the results of combining two bits with the bitwise exclusive OR operator.
Bit 1 | Bit 2 | Bit 1 ^ Bit 2 |
---|---|---|
0 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
1 |
1 |
0 |
The bitwise complement operator (~
) sets all 1
bits in its operand to 0
in the result and sets all 0
bits to 1
in the result—otherwise referred to as “taking the one’s complement of the value.” In Fig. 22.8, line 39 assigns variable number1
the value 21845
(00000000 00000000 01010101 01010101
). When the expression ~number1
evaluates, the result is (11111111 11111111 10101010 10101010
).
Figure 22.11 demonstrates the left-shift operator (<<
) and the right-shift operator (>>
). Function displayBits
(lines 26–43) prints the unsigned
integer values.
The left-shift operator (<<
) shifts the bits of its left operand to the left by the number of bits specified in its right operand. Bits vacated to the right are replaced with 0
s; bits shifted off the left are lost. In Fig. 22.11, line 10 initializes variable number1
with the value 960
(00000000 00000000 00000011 11000000
). The result of left-shifting variable number1
eight bits in the expression number1 << 8
(line 16) is 245760
(00000000 00000011 11000000 00000000
).
The right-shift operator (>>
) shifts the bits of its left operand to the right by the number of bits specified in its right operand. Performing a right shift on an unsigned
integer causes the vacated bits at the left to be replaced by 0s; bits shifted off the right are lost. In the program of Fig. 22.11, the result of right-shifting number1
in the expression number1 >> 8
(line 22) is 3
(00000000 00000000 00000000 00000011
).
The result of shifting a value is undefined if the right operand is negative or if the right operand is greater than or equal to the number of bits in which the left operand is stored.
The result of right-shifting a signed value is machine dependent. Some machines fill with zeros and others use the sign bit.
Each bitwise operator (except the bitwise complement operator) has a corresponding assignment operator. These bitwise assignment operators
are shown in Fig. 22.12; they’re used in a similar manner to the arithmetic assignment operators introduced in Chapter 4.
Bitwise assignment operators | |
---|---|
&= |
Bitwise AND assignment operator. |
|= |
Bitwise inclusive OR assignment operator. |
^= |
Bitwise exclusive OR assignment operator. |
<<= |
Left-shift assignment operator. |
>>= |
Right-shift with sign extension assignment operator. |
Figure 22.13 shows the precedence and associativity of the operators introduced up to this point in the text. They’re shown top to bottom in decreasing order of precedence.
Operators | Associativity | Type |
---|---|---|
:: (unary; right to left) |
left to right | primary |
:: (binary; left to right)() (grouping parentheses) |
[See caution in Fig. 2.10 regarding grouping parentheses.] | |
() [] . -> ++ -- static_cast< type>() |
left to right | postfix |
++ -- + - ! delete sizeof * ~ & new |
right to left | prefix |
* / % |
left to right | multiplicative |
+ - |
left to right | additive |
<< >> |
left to right | shifting |
< <= > >= |
left to right | relational |
== != |
left to right | equality |
& |
left to right | bitwise AND |
^ |
left to right | bitwise XOR |
| |
left to right | bitwise OR |
&& |
left to right | logical AND |
|| |
left to right | logical OR |
?: |
right to left | conditional |
= += -= *= /= %= &= |= ^= <<= >>= |
right to left | assignment |
, |
left to right | comma |
As of C++14, you may now include binary literals
in your source code. To do so, precede a sequence of 1s and 0s with 0b
or 0B
. For example, you can define a 32-bit mask like the one we used in the displayBits
functions of this section’s examples as
0b10000000'00000000'00000000'00000000
The preceding literal also uses C++14’s single-quote character to separate groups of digits for readability.