More on Handling Basic Data Types - Try It Out: Using the Bitwise Operators
(Page 7 of 13 )
You can put together an example that exercises the bitwise operators, so that you can see them working together. You can also illustrate the use of the exclusive OR for switching between two values, and how you use masks to select and set individual bits. Here’s the code:
// Program 3.4 Using the bitwise operators
#include <iostream>
#include <iomanip>
using std::cout;
using std::endl;
using std::setfill;
using std::setw;
int main() {
unsigned long red = 0XFF0000UL; // Color red
unsigned long white = 0XFFFFFFUL; // Color white - RGB
all maximum
cout << std::hex; // Set hexadecimal
output format
cout << setfill('0'); // Set fill character
for output
cout << "\nTry out bitwise AND and OR operators.";
cout << "\nInitial value red = " << setw(8) << red;
cout << "\nComplement ~red = " << setw(8) << ~red;
cout << "\nInitial value white = " << setw(8) << white;
cout << "\nComplement ~white = " << setw(8) <<
~white;
cout << "\n Bitwise AND red & white = " << setw(8) <<
(red & white);
cout << "\n Bitwise OR red | white = " << setw(8) <<
(red | white);
cout << "\n\nNow we can try out successive exclusive OR
operations.";
unsigned long mask = red ^ white;
cout << "\n mask = red ^ white = " << setw(8) <<
mask;
cout << "\n mask ^ red = " << setw(8) <<
(mask ^ red);
cout << "\n mask ^ white = " << setw(8) <<
(mask ^ white);
unsigned long flags = 0xFF; // Flags variable
unsigned long bit1mask = 0x1; // Selects bit 1
unsigned long bit6mask = 0x20; // Selects bit 6
unsigned long bit20mask = 0x80000; // Selects bit 20
cout << "\n\nNow use masks to select or set a particular
flag bit.";
cout << "\nSelect bit 1 from flags : " << setw(8) <<
(flags & bit1mask);
cout << "\nSelect bit 6 from flags : " << setw(8) <<
(flags & bit6mask);
cout << "\nSwitch off bit 6 in flags : " << setw(8) <<
(flags &= ~bit6mask);
cout << "\nSwitch on bit 20 in flags : " << setw(8) <<
(flags |= bit20mask);
cout << endl;
return 0;
}This example produces the following output:
======================================================
Try out bitwise AND and OR operators.
Initial value red = 00ff0000
Complement ~red = ff00ffff
Initial value white = 00ffffff
Complement ~white = ff000000
Bitwise AND red & white = 00ff0000
Bitwise OR red | white = 00ffffff
Now we can try out successive exclusive OR operations.
mask = red ^ white = 0000ffff
mask ^ red = 00ffffff
mask ^ white = 00ff0000
Now use masks to select or set a particular flag bit.
Select bit 1 from flags : 00000001
Select bit 6 from flags : 00000020
Switch off bit 6 in flags : 000000df
Switch on bit 20 in flags : 000800df
====================================================
HOW IT WORKS
There is an #include directive for the <iomanip> standard header, which you saw in the last chapter, because the code uses manipulators to control the formatting of the output. To start with, you define two integer variables containing values representing the colors that you’ll use in subsequent bitwise operations:
unsigned long red = 0XFF0000UL; // Color red
unsigned long white = 0XFFFFFFUL; // Color white - RGB
all maximum
You’ll want to display your data as hexadecimal values, so you specify this with this statement:
cout << std::hex; // Set hexadecimal output format
Here, hex is a manipulator that sets the output representation for integer values as hexadecimal. Note that this is modal—all subsequent integer output to the standard output stream in the program will now be in hexadecimal format. You don’t need to keep sending hex to the output stream, cout. If necessary, you could change back to decimal output with this statement:
cout << std::dec; // Set decimal output format
This uses the dec manipulator to reset integer output to the default decimal representation. Note that setting the output format to hexadecimal only affects integer values. Floating-point values will continue to be displayed in normal decimal form.
It would also make things clearer if you output your integers with leading zeros, and you set this mode with this statement:
cout << setfill('0'); // Set fill character for output
Here, setfill() is a manipulator that sets the fill character to whatever character you put between the parentheses. This is also modal, so any subsequent integer output will use this fill character when necessary. Both decimal and hexadecimal output is affected. If you wanted asterisks instead, you would use this:
cout << setfill('*'); // Set fill character for output
To set the fill character back to the default, you just use a space between the parentheses:
cout << setfill(' '); // Set fill character for output
The value of red and its complement are displayed by these statements:
cout << "\nInitial value red = " << setw(8) << red;
cout << "\nComplement ~red = " << setw(8) << ~red;
You use the setw() manipulator that you saw in the last chapter to set the output field width to 8. If you make sure all your output values will be in a field of the same width, it will be easier to compare them. Setting the width is not modal; it only applies to the output from the next statement that comes after the point at which the width is set. From the output for red and white, you can see that the ~ operator is doing what you expect: flipping the bits of its operand.
You combine red and white using the bitwise AND and OR operators with these statements:
cout << "\n Bitwise AND red & white = " << setw(8) <<
(red & white);
cout << "\n Bitwise OR red | white = " << setw(8) <<
(red | white);
Notice the parentheses around the expressions in the output. These are necessary because the precedence of << is higher than & and |. Without the parentheses, the statements wouldn’t compile. If you check the output, you’ll see that it’s precisely as discussed. The result of ANDing two bits is 1 if both bits are 1; otherwise the result is 0. When you bitwise-OR two bits, the result is 1 unless both bits are 0.
Next, you create a mask to use to flip between the values red and white by combining the two values with the exclusive OR operator:
unsigned long mask = red ^ white;
If you inspect the output for the value of mask, you’ll see that the exclusive OR of two bits is 1 when the bits are different and 0 when they’re the same. By combining mask with either of the two color values using exclusive OR, you can obtain the other, as demonstrated by these statements:
cout << "\n mask ^ red = " << setw(8) << (mask
^ red);
cout << "\n mask ^ white = " << setw(8) << (mask
^ white);
The last group of statements demonstrates how to use a mask to select a single bit from a group of flag bits. The mask to select a particular bit must have that bit as 1 and all other bits as 0. Thus, the masks to select bits 1, 6, and 20 from a 32-bit long variable are defined as follows:
unsigned long bit1mask = 0x1; // Selects bit 1
unsigned long bit6mask = 0x20; // Selects bit 6
unsigned long bit20mask = 0x80000; // Selects bit 20
To select a bit from flags, you just need to bitwise-AND the appropriate mask with the value of flags, for example:
cout << "\nSelect bit 6 from flags : " << setw(8) <<
(flags & bit6mask);
You can see from the output that the result of the expression (flags & bit6mask) is an integer with just bit 6 set. Of course, if bit 6 in flags was 0, the result of the expression would be 0.
To switch a bit off, you need to bitwise-AND the flags variable with a mask containing 0 for the bit you want to switch off and 1 everywhere else. You can easily produce this by applying the complement operator to a mask with the appropriate bit set, and bit6mask is just such a mask. The statement to switch off bit 6 in flags and display the result is as follows:
cout << "\nSwitch off bit 6 in flags : " << setw(8) <<
(flags &= ~bit6mask);
Of course, if bit 6 were already 0, it would remain as such. To switch a bit on, you just OR flags with a mask having the bit you want to switch on as 1:
cout << "\nSwitch on bit 20 in flags : " << setw(8) <<
(flags |= bit20mask);
This sets bit 20 of flags to 1 and displays the result. Again, if the bit were already 1, it would remain as 1.
This article is excerpted from Beginning ANSI C++ The Complete Language by Ivor Horton (Apress, 2004; ISBN 1590592271). Check it out at your favorite bookstore today. Buy this book now. |
Next: More on Output Manipulators >>
More C++ Articles
More By Apress Publishing