Contents  1-5  6-11  12-16  17-21  22-27   28-33  34 - 38  39-46  Projects   MFC

   Contact
   Search
   C
   C++
   Visual Basic
   Java
   JavaScript
   DHTML
   Style Sheets
   About
   Active X
   TDC Binding
   PHP
   Perl and CGI
   Flash
   XML
   SQL
   Messages
   Chat
   MCSE
   Linux
   Cabling   
   ActionScript
   Downloads
   E-Cards   
 
    
    

Bitwise operators allow the C++ programmer to control and manipulate individual bits of memory.  This can be useful
for setting "flags" on objects to determine what state they are in.   Each byte is composed of 8 bits, so in a 4 byte long
there would be 32 bits.  Each bit can be used for a flag, so that's 32 possible flags.  When we set a bit, we make its
value 1.  When we clear it, we make it 0.  It boils down to on/of - binary.  Manipulating bits via bitwise operators is know as "bit twiddling".  The bitwise operators are used to set individual bits.  They look very similar to the logical operators, but they are shorter.  Let's take a look:

& - AND, = 1 if both bits are 1, but 0 if either or both bits are 0.
| - OR, = 1 if either bit is set or if both are set.
^ - exclusive OR, = 1 if the two bits are different.
~ - complement, = clears every bit in a number that's set, and sets every bit in a number that's clear.  Like: 1010011 = 0101 1100
<< - shift left, = shifts bits to the left
>> - shift right, = shifts bits to the right

Masking operations - Used to set a particular bit.  For a 4 byte flag, to set the 8th bit to true, you would need to OR the flag with 128.  It's 128 because 27 is 128, and that 27 is the 8th bit place in the byte.  Remember:   128  64  32  16  8  4  2  1 .  So 128 = 1000 0000 in binary, the 8th bit is switched on and the other 7 are switched off. 

Bit Fields - Using bit fields can save memory .  Using built-in data types, the smallest type is a char, which is 1 byte (8 bits).  Using bit fields, you could store 8 binary values in 1 byte.  That's 8 possible on's and off's, which could be used like Booleans.   A bitfield's type is always declared to be an unsigned int.  After declaring the bitfield's name, a colon is written followed by a number.  The number refers to how many bitsare assigned to the variable.  Syntax:
 unsigned MyBitField : 1;  Example:

unsigned MyBitField : 1 =  2 possible values, (on | off).
unsigned MyBitField : 2 =  4 possible values, (on, on  | off, off  |  on, off  |  off, on).
unsigned MyBitField : 3 =  8 possible values, (and so on and so on ...)

The example below conserves memory by using bitfields and many enumerated constants to do its job.  Recall that enumerated constants, like elements in an array, all have numerical index-like values, starting at 0 and advancing, unless otherwise specified.

#include <iostream>
using namespace std;
#include <string.h>
enum STATUS { FullTime, PartTime } ;
enum SalaryLevel { E1, E2 } ;
enum HOUSING { Dorm, OffCampus };
enum BenefitPlan { Partial, Full, FullFamily, NoBenefits };
class Employee
{
public:
	Employee():
		myStatus(FullTime),
		mySalaryLevel(E1),
		myHousing(Dorm),
		myBenefitPlan(NoBenefits)
	{}

	~Employee(){}


	STATUS GetStatus();
	void SetStatus(STATUS);
	unsigned GetPlan() { return myBenefitPlan; }
private:
        //Note:  These are bit fields, and as such use much les memory than bools or int's
	unsigned myStatus : 1;
	unsigned mySalaryLevel: 1;
	unsigned myHousing : 1;
	unsigned myBenefitPlan : 2;
};
STATUS Employee::GetStatus()
{
	if(myStatus)
		return FullTime;
	else
		return PartTime;
}
void Employee::SetStatus(STATUS theStatus)
{
	myStatus = theStatus;
}
int main()
{
	Employee Orion;
	if(Orion.GetStatus()== PartTime)
		cout << "Orion is part time" << endl;
	else
		cout << "Orion is full time" << endl;
	Orion.SetStatus(PartTime);
	if(Orion.GetStatus())
		cout << "Orion is part time" << endl;
	else
		cout << "Orion is full time" << endl;
	cout << "Orion is on the \"" ;
	char Plan[80];
	switch(Orion.GetPlan())
	{
	case Partial: strcpy(Plan,"partial benefits"); break;
	case Full: strcpy(Plan,"full benefits"); break;
	case FullFamily: strcpy(Plan,"full Family Benefits"); break;
	case NoBenefits: strcpy(Plan,"no benefits");break;
	default : cout << "Something bad went wrong!\n"; break;
	}
	cout << Plan << "\" benefit plan." << endl;

	return 0;
}

Let's look at a further breakdown of these bitwise operators:

char var1 = 'A';    //0x41 in hex
char var2 = 'Z';    //0x5A in hex
char result = 0;     //Hold result

Bitwise AND - Truth Table
 

Bitwise AND 0 1
0 0 0
1 0 1

Example:
result = var1 &  var2;

var1 = 0 1 0 0 0 0 0 1
var2 = 0 1 0 1 1 0 1 0
result = 0 1 0 0 0 0 0 0

 

Bitwise OR (inclusive) - Truth Table

Bitwise OR 0 1
0 0 1
1 1 1

Example:
result = var1 |  var2;

var1 = 0 1 0 0 0 0 0 1
var2 = 0 1 0 1 1 0 1 0
result = 0 1 0 1 1 0 1 1

 

Bitwise Exclusive OR - Truth Table

Bitwise AND 0 1
0 0 1
1 1 0

Example:
result = var1 ^  var2;

var1 = 0 1 0 0 0 0 0 1
var2 = 0 1 0 1 1 0 1 0
result = 0 0 0 1 1 0 1 1

 

Bitwise NOT

Example:
result = ~var2;
 
var2 = 0 1 0 1 1 0 1 0
result = 1 0 1 0 0 1 0 1

 

Inverts the bits - 0's become 1's and 1's become 0's. 

Bitwise Shifts:

Left Shift:
unsigned int num = 16387u;   //Adding the "u" since its an unsigned integer literal
num <<= 2;

                          Shifting to the left by 2 places
 

Powers of 2: 32,768 16,384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1
16,387 = 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1
Shift left 2 places = 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
Result = 12 In decimal, the number 12.   (8 + 4 = 12).  The "1" in the 16,384's place is lost.

In the example above, the bit switched off in the 32,768's place and the one switched on in the 16,384's place are shifted to the left two places.  This means they "fall off", that is, they are discarded, so that the bits at the right end can be moved over two places to the left.

 

Right Shift:
unsigned int num = 16387u;   //Adding the "u" since its an unsigned integer literal
num >>= 2;

 

Powers of 2: 32,768 16,384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1
16,387 = 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1
Shift right 2 places = 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Result = 4096 In decimal, the number 4096.   The "1" in the 2's and 1's place is lost.

In the example above, the bit switched off in the 32,768's place and the one switched on in the 16,384's place are shifted to the right two places.  This causes the two bits on the right end to "fall off", that is, they are discarded, so that the bits at the right end no longer have values in the 2 and 1's place.

 


©2004 C. Germany