Author : GHA
Page : 1 Next >>
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 >>