Bitwise Operators

C++ provides extensive bit-manipulation capabilities for programmers who need to get down to the so-called "bits-and-bytes" level. Operating systems, test-equipment software, networking software and many other kinds of software require that the programmer communicate "directly with the hardware." In this and the next several sections, we discuss C++'s bit-manipulation capabilities. We introduce each of C++'s many 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 8 bits forms a bytethe 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). Unsigned integers are normally used with the bitwise operators.

Portability Tip 22.3

Bitwise data manipulations are machine dependent.

Note that 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, Number Systems. 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 (|), itwise exclusive OR (^), left shift (<<), right shift (>>) and bitwise complement (~)also known as the one's complement. (Note that we have 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 operandbut not bothis 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.


Figure 22.5. Bitwise operators.

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.

 

Printing a Binary Representation of an Integral Value

When using the bitwise operators, it is 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.

Figure 22.6. Printing an unsigned integer in bits.

(This item is displayed on pages 1066 - 1067 in the print version)

 1 // Fig. 22.6: fig22_06.cpp
 2 // Printing an unsigned integer in bits.
 3 #include 
 4 using std::cout;
 5 using std::cin;
 6 using std::endl;
 7
 8 #include 
 9 using std::setw;
10
11 void displayBits( unsigned ); // prototype
12
13 int main()
14 {
15 unsigned inputValue; // integral value to print in binary
16
17 cout << "Enter an unsigned integer: ";
18 cin >> inputValue;
19 displayBits( inputValue );
20 return 0;
21 } // end main
22
23 // display bits of an unsigned integer value
24 void displayBits( unsigned value )
25 {
26 const int SHIFT = 8 * sizeof( unsigned ) - 1;
27 const unsigned MASK = 1 << SHIFT; 
28
29 cout << setw( 10 ) << value << " = ";
30
31 // display bits
32 for ( unsigned i = 1; i <= SHIFT + 1; i++ )
33 {
34 cout << ( value & MASK ? '1' : '0' );
35 value <<= 1; // shift value left by 1
36
37 if ( i % 8 == 0 ) // output a space after 8 bits
38 cout << ' ';
39 } // end for
40
41 cout << endl;
42 } // end function displayBits
 
 Enter an unsigned integer: 65000
 65000 = 00000000 00000000 11111101 11101000
 
 
 Enter an unsigned integer: 29
 29 = 00000000 00000000 00000000 00011101
 

Function displayBits (lines 2442) uses the bitwise AND operator to combine variable value with constant MASK. Often, the bitwise AND operator is used with an operand called a maskan 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 27 assigns constant MASK the value 1 << SHIFT. The value of constant SHIFT was calculated in line 26 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 34 determines whether a 1 or a 0 should be printed 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 35 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 1s, the result of the expression is nonzero (true) and a value of 1 is printed. Figure 22.7 summarizes the results of combining two bits with the bitwise AND operator.

Figure 22.7. 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

Common Programming Error 22.3

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 5775) prints the unsigned integer values.

Figure 22.8. Bitwise AND, bitwise inclusive-OR, bitwise exclusive-OR and bitwise complement operators.

(This item is displayed on pages 1069 - 1070 in the print version)

 1 // Fig. 22.8: fig22_08.cpp
 2 // Using the bitwise AND, bitwise inclusive OR, bitwise
 3 // exclusive OR and bitwise complement operators.
 4 #include 
 5 using std::cout;
 6
 7 #include 
 8 using std::endl;
 9 using std::setw;
10
11 void displayBits( unsigned ); // prototype
12
13 int main()
14 {
15 unsigned number1;
16 unsigned number2;
17 unsigned mask;
18 unsigned setBits;
19
20 // demonstrate bitwise &
21 number1 = 2179876355;
22 mask = 1;
23 cout << "The result of combining the following
";
24 displayBits( number1 );
25 displayBits( mask );
26 cout << "using the bitwise AND operator & is
";
27 displayBits( number1 & mask );
28
29 // demonstrate bitwise |
30 number1 = 15;
31 setBits = 241;
32 cout << "
The result of combining the following
";
33 displayBits( number1 );
34 displayBits( setBits );
35 cout << "using the bitwise inclusive OR operator | is
";
36 displayBits( number | setbits );
37
38 // demonstrate bitwise exclusive OR
39 number1 = 139;
40 number2 = 199;
41 cout << "
The result of combining the following
";
42 displayBits( number1 );
43 displayBits( number2 );
44 cout << "using the bitwise exclusive OR operator ^ is
";
45 displayBits( number ^ number2 );
46
47 // demonstrate bitwise complement
48 number1 = 21845;
49 cout << "
The one's complement of
";
50 displayBits( number1 );
51 cout << "is" << endl;
52 displayBits( ~number1 );
53 return 0;
54 } // end main
55
56 // display bits of an unsigned integer value
57 void displayBits( unsigned value )
58 {
59 const int SHIFT = 8 * sizeof( unsigned ) - 1;
60 const unsigned MASK = 1 << SHIFT;
61
62 cout << setw( 10 ) << value << " = ";
63
64 // display bits
65 for ( unsigned i = 1; i <= SHIFT + 1; i++ )
66 {
67 cout << ( value & MASK ? '1' : '0' );
68 value <<= 1; // shift value left by 1
69
70 if ( i % 8 == 0 ) // output a space after 8 bits
71 cout << ' ';
72 } // end for
73
74 cout << endl;
75 } // end function displayBits
 
 The result of combining the following
 2179876355 = 10000001 11101110 01000110 00000011
 1 = 00000000 00000000 00000000 00000001
 using the bitwise AND operator & is
 1 = 00000000 00000000 00000000 00000001

 The result of combining the following
 15 = 00000000 00000000 00000000 00001111
 241 = 00000000 00000000 00000000 11110001
 using the bitwise inclusive OR operator | is
 255 = 00000000 00000000 00000000 11111111

 The result of combining the following
 139 = 00000000 00000000 00000000 10001011
 199 = 00000000 00000000 00000000 11000111
 using the bitwise exclusive OR operator ^ is
 76 = 00000000 00000000 00000000 01001100

 The one's complement of
 21845 = 00000000 00000000 01010101 01010101
 is
 4294945450 = 11111111 11111111 10101010 10101010
 

Bitwise AND Operator (&)

In Fig. 22.8, line 21 assigns 2179876355 (10000001 11101110 01000110 00000011) to variable number1, and line 22 assigns 1 (00000000 00000000 00000000 00000001) to variable mask. When mask and number1 are combined using the bitwise AND operator (&) in the expression number1 & mask (line 27), 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.


Bitwise Inclusive OR Operator (|)

The bitwise inclusive-OR operator is used to set specific bits to 1 in an operand. In Fig. 22.8, line 30 assigns 15 (00000000 00000000 00000000 00001111) to variable number1, and line 31 assigns 241 (00000000 00000000 00000000 11110001) to variable setBits. When number1 and setBits are combined using the bitwise OR operator in the expression number1 | setBits (line 36), the result is 255 (00000000 00000000 00000000 11111111). Figure 22.9 summarizes the results of combining two bits with the bitwise inclusive-OR operator.


Figure 22.9. Combining two bits with the bitwise inclusive-OR operator (|).

Bit 1

Bit 2

Bit 1 | Bit 2

0

0

0

1

0

1

0

1

1

1

1

1

Common Programming Error 22.4

Using the logical OR operator (||) for the bitwise OR operator (|) and vice versa is a logic error.

 

Bitwise Exclusive OR (^)

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 3940 assign 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 exclusive-OR operator in the expression number1 ^ number2 (line 45), the result is 00000000 00000000 00000000 01001100. Figure 22.10 summarizes the results of combining two bits with the bitwise exclusive-OR operator.

Figure 22.10. 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

 

Bitwise Complement (~)

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 resultotherwise referred to as "taking the one's complement of the value." In Fig. 22.8, line 48 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 3149) prints the unsigned integer values.

Figure 22.11. Bitwise shift operators.

(This item is displayed on pages 1072 - 1073 in the print version)

 1 // Fig. 22.11: fig22_11.cpp
 2 // Using the bitwise shift operators.
 3 #include 
 4 using std::cout;
 5 using std::endl;
 6
 7 #include 
 8 using std::setw;
 9
10 void displayBits( unsigned ); // prototype
11
12 int main()
13 {
14 unsigned number1 = 960;
15
16 // demonstrate bitwise left shift
17 cout << "The result of left shifting
";
18 displayBits( number1 );
19 cout << "8 bit positions using the left-shift operator is
";
20 displayBits( number1 << 8 );
21
22 // demonstrate bitwise right shift
23 cout << "
The result of right shifting
";
24 displayBits( number1 );
25 cout << "8 bit positions using the right-shift operator is
";
26 displayBits( number1 >> 8 );
27 return 0;
28 } // end main
29
30 // display bits of an unsigned integer value
31 void displayBits( unsigned value )
32 {
33 const int SHIFT = 8 * sizeof( unsigned ) - 1;
34 const unsigned MASK = 1 << SHIFT;
35
36 cout << setw( 10 ) << value << " = ";
37
38 // display bits
39 for ( unsigned i = 1; i <= SHIFT + 1; i++ )
40 {
41 cout << ( value & MASK ? '1' : '0' );
42 value <<= 1; // shift value left by 1
43
44 if ( i % 8 == 0 ) // output a space after 8 bits
45 cout << ' ';
46 } // end for
47
48 cout << endl;
49 } // end function displayBits
 
 The result of left shifting
 960 = 00000000 00000000 00000011 11000000
 8 bit positions using the left-shift operator is
 245760 = 00000000 00000011 11000000 00000000

 The result of right shifting
 960 = 00000000 00000000 00000011 11000000
 8 bit positions using the right-shift operator is
 3 = 00000000 00000000 00000000 00000011
 

Left-Shift Operator

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 0s; bits shifted off the left are lost. In the program of Fig. 22.11, line 14 assigns variable number1 the value 960 (00000000 00000000 00000011 11000000). The result of left-shifting variable number1 8 bits in the expression number1 << 8 (line 20) is 245760 (00000000 00000011 11000000 00000000).


Right-Shift Operator

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 26) is 3 (00000000 00000000 00000000 00000011).

Common Programming Error 22.5

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.

Portability Tip 22.4

The result of right-shifting a signed value is machine dependent. Some machines fill with zeros and others use the sign bit.

 

Bitwise Assignment Operators

Each bitwise operator (except the bitwise complement operator) has a corresponding assignment operator. These bitwise assignment operators are shown in Fig. 22.12; they are used in a similar manner to the arithmetic assignment operators introduced in Chapter 2.

Figure 22.12. Bitwise assignment operators.

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 are shown top to bottom in decreasing order of precedence.

Figure 22.13. Operator precedence and associativity.

Operators

Associativity

Type

:: (unary; right to left)

:: (binary; left to right)

left to right

highest

()

[]

.

->

++

--

static_cast< type >()

left to right

unary

++

--

+

-

!

delete sizeof

right to left

unary

*

~

&

new

                 

*

/

%

               

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


Introduction to Computers, the Internet and World Wide Web

Introduction to C++ Programming

Introduction to Classes and Objects

Control Statements: Part 1

Control Statements: Part 2

Functions and an Introduction to Recursion

Arrays and Vectors

Pointers and Pointer-Based Strings

Classes: A Deeper Look, Part 1

Classes: A Deeper Look, Part 2

Operator Overloading; String and Array Objects

Object-Oriented Programming: Inheritance

Object-Oriented Programming: Polymorphism

Templates

Stream Input/Output

Exception Handling

File Processing

Class string and String Stream Processing

Web Programming

Searching and Sorting

Data Structures

Bits, Characters, C-Strings and structs

Standard Template Library (STL)

Other Topics

Appendix A. Operator Precedence and Associativity Chart

Appendix B. ASCII Character Set

Appendix C. Fundamental Types

Appendix D. Number Systems

Appendix E. C Legacy Code Topics

Appendix F. Preprocessor

Appendix G. ATM Case Study Code

Appendix H. UML 2: Additional Diagram Types

Appendix I. C++ Internet and Web Resources

Appendix J. Introduction to XHTML

Appendix K. XHTML Special Characters

Appendix L. Using the Visual Studio .NET Debugger

Appendix M. Using the GNU C++ Debugger

Bibliography



C++ How to Program
C++ How to Program (5th Edition)
ISBN: 0131857576
EAN: 2147483647
Year: 2004
Pages: 627

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net