C++ Bitwise Operations And Hexadecimal Representation

Brad Vander Zanden


C++ provides 2 types of bitwise operations that we will be using in this course:

  1. bitwise shift operations, and
  2. bitwise logic operations.

Bitwise operations can be performed on either integers or chars.


Shift Operations

The << operator shifts bits n bits to the left and the >> operator shifts bits n bits to the right. Here are several examples assuming that integers are 8 bit quantities:

i = 6        // i = 00000110
i = i << 3   // i = 00110000   (48 in base 10)

i = 86       // i = 01010110
i = i << 3   // i = 10110000 (176 in base 10) -- leftmost 3 bits thrown away

i = 86       // i = 01010110
i = i >> 3   // i = 00001010 (10 in base 10) -- rightmost 3 bits thrown away

i = 6        // i = 00000110
i = i >> 3   // i = 00000000 -- rightmost 3 bits thrown away
Notice that the left shift operator throws away the leftmost three bits and adds three 0 bits at the end of the string. Similarly, the right shift operator "throws away" the rightmost three bits and adds three 0 bits to the beginning of the string. In general, left shifting by n bits throws away the leftmost n bits and adds n 0 bits to the right side of the string (thus multiplying the string by 2n). Similarly, right shifting by n bits throws away the rightmost n bits and adds n 0 bits to the left side of the string (thus dividing the string by 2n).


Bitwise Logic Operators

The bitwise logic operators perform bitwise logic operations on each pair of bits in the two operands. There are three bitwise logic operators:

  1. or: a | b
  2. and: a & b
  3. exclusive or (xor): a ^ b

The truth tables for these three operators are as follows:

or
abresult
000
011
101
111
and
abresult
000
010
100
111
xor
abresult
000
011
101
110

Here are some examples:

0110 | 1010 = 1110

0110 & 1010 = 0010

0110 ^ 1010 = 1100
To see how each of these results get computed, put the second operand under the first, like you might do in an arithmetic operation:
  0110
| 1010
  ----
  1110

  0110
& 1010
  ----
  0010

  0110
^ 1010
  ----
  1100

In a real program, you might actually write:

int a = 6;    // a = 0110
int b = 10;   // b = 1010
int c = a | b; // c = 1110 (14 in base 10)

Uses for the Bit Manipulation Operations

You will see that there are many uses for bit manipulation operations as you proceed through your computer science courses. Here are a few uses in this course:

  1. For fast multiplication or division by powers of two
  2. For computation of hash functions
  3. For clearing or setting flags. As an example, the way cin implements its fail, clear, and eof functions is that it keeps bits (called flags) that indicate the status of eof (e.g., 0 is not eof and 1 is eof, or 0 is not failure and 1 is failure). clear() would use bitwise and with 0's to clear the flags (since anding with 0 always yields 0). To set a flag to 1, you would or the flag bit with 1, which always yields a 1, regardless of the previous status of the flag.


Hexadecimal Representation

It is tiresome to have to write out binary strings and so computer scientists often write out hexadecimal strings instead. If you remember from COSC 130, hexadecimal is base 16. Here are the conversion tables in case you have forgotten them:

binary (base 2)decimal (base 10)hexadecimal (base 16)
000000
000111
001022
001133
010044
010155
011066
011177
100088
100199
101010A
101111B
110012C
110113D
111014E
111115F

We can replace each string of 4 binary digits with a single hexadecimal digit. For example:

0100 1100 1010 0100 1111 0010 1011 0111 = 0x4CA4F2B7
We typically write 0x in front of a hexadecimal string to make it clear that the string is a hexadecimal number. You can get printf to print a number in hexadecimal format using the %x directive. For example:
unsigned int x = 14;
unsigned int y = 2593
printf("x = %x\n", x);
printf("y = %x\n", y);
will print
x = e
y = a21
You should become proficient both at converting binary strings to hexadecimal strings and hexadecimal strings to binary strings. Notice that printf does not put 0x in front of the result, so more typically you would put a 0x in front of the formatting directive as follows:
unsigned int x = 14;
unsigned int y = 2593
printf("x = 0x%x\n", x);
printf("y = 0x%x\n", y);
will print
x = 0xe
y = 0xa21