I l@ve RuBoard |
![]() ![]() |
11.7 Setting, Clearing, and Testing BitsA character contains eight bits.[1] Each of these can be treated as a separate flag. Bit operations can be used to pack eight single-bit values in a single byte. For example, suppose you are writing a low-level communications program. You are going to store the characters in an 8K buffer for later use. With each character, you will also store a set of status flags. The flags are listed in Table 11-8.
You could store each flag in its own character variable. That would mean that for each character buffered, you would need five bytes of status storage. For a large buffer, that adds up. By instead assigning each status flag its own bit within an eight-bit status character, you cut storage requirements down to 1/5 of the original need. You can assign the flags the bit numbers listed in Table 11-9.
Bits are numbered 76543210 by convention. The constants for each bit are defined in Table 11-10.
Here's one way we can define constants for the bits that make up the communication status values: // True if any error is set const int ERROR = 0x01; // A framing error occurred for this character const int FRAMING_ERROR = 0x02; // Character had the wrong parity const int PARITY_ERROR = 0x04; // The carrier signal went down const int CARRIER_LOST = 0x08; // Power was lost on the communication device const int CHANNEL_DOWN = 0x10; This method of defining bits is somewhat confusing. Can you tell (without looking at the table) which bit number is represented by the constant 0x10? Table 11-11 shows how you can use the left shift operator (<<) to define bits.
Although it is hard to tell what bit is represented by 0x10, it's easy to tell what bit is meant by 1 << 4. Here's another way of defining the constants for testing the communication status bits: // True if any error is set const int ERROR = (1 << 0); // A framing error occurred for this character const int FRAMING_ERROR = (1 << 1); // Character had the wrong parity const int PARITY_ERROR = (1 << 2); // The carrier signal went down const int CARRIER_LOST = (1 << 3); // Power was lost on the communication device const int CHANNEL_DOWN = (1 << 4); Now that you have defined the bits, you can manipulate them. To set a bit, use the | operator. For example: char flags = 0; // Start all flags at 0 flags |= CHANNEL_DOWN; // Channel just died To test a bit, use the & operator to "mask out" the bits: if ((flags & ERROR) != 0) std::cerr << "Error flag is set\n"; else std::cerr << "No error detected\n"; Clearing a bit is a little harder. Suppose you want to clear the bit PARITY_ERROR. In binary this bit is 00000100. You want to create a mask that has all bits set except for the bit you want to clear (11111011). This is done with the NOT operator (~). The mask is then ANDed with the number to clear the bit. PARITY_ERROR 00000100 ~PARITY_ERROR 11111011 flags 00000101 ___________________________________________ flags & ~PARITY_ERROR 00000001 In C++ this is: flags &= ~PARITY_ERROR; // Who cares about parity Question 11-1: In the following program, the HIGH_SPEED flag works, but the DIRECT_CONNECT flag does not. Why? #include <iostream> const int HIGH_SPEED = (1<<7); /* modem is running fast */ // we are using a hardwired connection const int DIRECT_CONNECT = (1<<8); char flags = 0; // start with nothing int main( ) { flags |= HIGH_SPEED; // we are running fast flags |= DIRECT_CONNECT; // because we are wired together if ((flags & HIGH_SPEED) != 0) std::cout <<"High speed set\n"; if ((flags & DIRECT_CONNECT) != 0) std::cout <<"Direct connect set\n"; return (0); } ![]() |
I l@ve RuBoard |
![]() ![]() |