Topic : Bit-wise Logical Operators
Author : GHA
Page : 1 Next >>
Go to page :


Bit-wise Logical Operators

Besides representing a number or a character, a memory location can be used for various purposes as a set of bits. For example, individual bits in a byte can represent "flags" that identify the propertyires or current state of an object or program. Combinations of bits may represent "fields" packed into one int or long memory location. Idividual bits may also represent pixels in an image, and bit patterns may be used in low-level routines for programming hardware registers.

Variables used as sets of bits can be declared as unsigned integral types. It makes sense to distinguish these variables from numeric and character variables by introducing special data types for them. The following data type names have become rather common:

   typedef unsigned char BYTE;
   typedef unsigned short WORD;
   typedef unsigned long DWORD;   // "double word"


A BYTE variable has eight bits. To make our discussion more concrete, let's assume that a WORD has two bytes (16 bits) and a DWORD, four bytes (32 bits). The individual bits are oten referred to by their positi9ons in a byte or a word, starting from 0 at the rightmost, least significant bit. For example, bits in a byte would be numbered 0 through 7 as is below (this is the usual numbering of bits in a byte):

   Bit 7 6 5 4 3 2 1 0

       0 1 0 0 1 1 0 1
      |_|_|_|_|_|_|_|_|

The easiest way to initialize variables that represent bit patterns in C++ is by using hexadecimal numbers. Eash hex digit corresponds to four bits, as follows:

Binar      Hex
0000      0
0001      1
0010      2
0011      3
0100      4
0101      5
0110      6
0111      7
1000      8
1001      9
1010      A
1011      B
1100      C
1101      D
1110      E
1111      F

C++ allows you to write a hex constant as a sequence of hex digits preceded by 0x. For example:

   WORD flags = 0x8020;      // 1000 0000 0010 0000
   WORD mask = 0xFFC0;      // 1111 1111 1100 0000
   BYTE data_ready_bit = 0x20;   // 0010 0000


A byte can be defined by two hex digits, a word by four hex digits, and a double word by eight hex digits.

It is useful to remember hex equivalents for the following bit patterns:

     Binar                                 Hex
00000000                           0x00 (or just 0)
00000001                           0x01
00000010                           0x02
00000100                           0x04
00001000                           0x08
00010000                           0x10
00100000                           0x20
01000000                           0x40
10000000                           0x80
    
11111111                           0xFF
11110000                           0xF0
00001111                           0x0F
    
0000000000000001             0x0001
...  
1000000000000000             0x8000
1111111100000000             0xFF00
0000000011111111             0x00FF
1111111111111111             0xFFFF

C++ offers four bit-wise logical operators: the binary operators "and," "or," and "xor," and a unary operator "not." These operators take operands of integral types, but the values of individual bits in the result are determined by the vlue of corresponding bits (bits in the same positions) in operands.

The "and" operator is denoted by the symbol '&'. In the & operation the resulting bit is 1 if and only if both corresponding bits in the two operands are 1.

For example:

   00010100 11100010
& 11111111 00000000
   -----------------
   00010100 00000000

Or, in hex representation:


   0x14E2 & 0xFF00 = 0x1400

The "or" operator is denoted by the symblo '|'. In the | operation, the resulting bit is 1 if and only if at least on of the corresponding bits in the two operands is 1.

For example:

   00010100 00010001
| 00000000 00111111
   -----------------
   00010100 00111111

Or, in hex representation:

   0x1411 | 0x003F = 0x14003F
The "xor" operator is denoted by the symbol '^'. In the ^ operation the resulting bit is 1 if and only if exactly one of the corresponding bits in the two operands is 1.

For example:

   00010100 11110001
^ 00000000 11111111
   -----------------
   00010100 00001110

Or, in hex representation:

   0x14F1 ^ 0x00FF = 0x140E
The "not" operator is a unary operator. It is denoted by '~'. In the ~ operation the resulting bit is set to 1 if the corresponding bit in the operand is 0 and to 0 if the corresponding bit in the operand is 1.

For example:

~ 00001111 00000001
   -----------------
   11110000 11111110

Or, in hex representation:

   ~0x0F01 = F0FE
&, |, and ^ have lower precendence than relational operators, including the == and != operators.

For example:

   ... (x & 0x0001 !=0)
is interpreted as:

   ... (x & (0x0001 != 0))
as opposed to the possible intended:

   ... ((x & 0x0001) != 0)
This is a potential source of nasty bugs. Its is always safer to use parentheses around binary bitwise operators.

The &, |, and ^ operators can be used in compound assingments. For Example:

   WORD flags = 0x0020;

   flags |= 0x8000;      // same as: flags = flags | 0x8000;
   flags &= 0x00C0;      // same as: flags = flags & 0x00C0;


The & operator can be used to test or reset a bit in a byte or word. For example:

   BYTE flag = 0;
   const BYTE data_ready_bit = 0x20;

   ...
   if (flags & data_ready_bit)   // Test the "data ready" bit
     ...
   ...
   flags &= ~data_ready_bit;   // Reset the "data ready" bit (to 0)

& can also be used to set a bit in a byte or word. For example:

   flags |= data_ready_bit;   // Set "data ready" bit to 1

the ^= operator is handy when you need to toggel a bit or a value. The following function calculates the alternating sum of numbers in an array and uses ^= to toggel the sign flag.

   double AlernatingSum(const gvector &x) {
      // Returns x[0] - x[1] + x[2] - x[3] + ... - (or +) x[n-1].

      double sum=0.;
    


Page : 1 Next >>