11.7 Setting, Clearing, and Testing Bits

I l @ ve RuBoard

A 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.

[1] This is true on every machine I know in use today, but there's nothing in the C++ standard that mandates how many bits must be in a character.

Table 11-8. Communications status values

Name

Description

ERROR

True if any error is set

FRAMING_ERROR

A framing error occurred for this character

PARITY_ERROR

Character had the wrong parity

CARRIER_LOST

The carrier signal went down

CHANNEL_DOWN

Power was lost on the communication device

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.

Table 11-9. Bit assignments

Bit

Name

ERROR

1

FRAMING_ERROR

2

PARITY_ERROR

3

CARRIER_LOST

4

CHANNEL_DOWN

Bits are numbered 76543210 by convention. The constants for each bit are defined in Table 11-10.

Table 11-10. Bit values

Bit

Binary value

Hex constant

7

10000000

0x80

6

01000000

0x40

5

00100000

0x20

4

00010000

0x10

3

00001000

0x08

2

00000100

0x04

1

00000010

0x02

00000001

0x01

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.

Table 11-11. The left shift operator and bit definition

C++ representation

Base 2 equivalent

Result (base 2)

Bit number

1 << 0

00000001 2 << 0

00000001 2

Bit 0

1 << 1

00000001 2 << 1

00000010 2

Bit 1

1 << 2

00000001 2 << 2

00000100 2

Bit 2

1 << 3

00000001 2 << 3

00001000 2

Bit 3

1 << 4

00000001 2 << 4

00010000 2

Bit 4

1 << 5

00000001 2 << 5

00100000 2

Bit 5

1 << 6

00000001 2 << 6

01000000 2

Bit 6

1 << 7

00000001 2 << 7

10000000 2

Bit 7

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


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

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