<Previous Lesson

Visual Programming

Next Lesson>

Lesson#6

Bitwise Operators and Macros

Bitwise Operators..................................................................................................2
List of bitwise operators ........................................................................................2
Example -- Convert to binary with bit operators ....................................................3
Problems ...........................................................................................................4
Typedef.................................................................................................................4
Macros ..................................................................................................................5
Macro Arguments..............................................................................................5
Typecasting ..........................................................................................................6
Types of Typecasting ........................................................................................6
Assertions .............................................................................................................7
Assertions and error-checking...........................................................................7
Turning assertions off........................................................................................8
The switch and case keywords .............................................................................8
Summary ............................................................................................................11
Tips .....................................................................................................................10
Bitwise Operators and Macros 2

Bitwise Operators

An operator that manipulates individual bits is called a bitwise operator. The most
familiar operators are the addition operator (+) etc and these operators work with bytes or
groups of bytes. Occasionally, however, programmers need to manipulate the bits within
a byte.
C++ provides operators to work with the individual bits in integers. For this to be useful,
we must have some idea of how integers are represented in binary. For example the
decimal number 3 is represented as 11 in binary and the decimal number 5 is represented
as 101 in binary.

List of bitwise operators

Purpose Operator example
complement ~i
and i&j
exclusive or i^j
inclusive or i|j
shift left i<<n
shift right i>>n
can be used on any integer type (char, short, int, etc.)
right shift might not do sign extension
used for unpacking compressed data

Bitwise AND operator

0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1

Bitwise OR operator

0 OR 0 = 0
0 OR 1 = 1
1 OR 0 = 1
1 OR 1 = 1

Bitwise OR operator

Bitwise Operators and Macros
3
0 XOR 0 = 0
0 XOR 1 = 1 x XOR 0 = x
1 XOR 0 = 1 x XOR 1 = ~x
1 XOR 1 = 0
Bitwise Left-Shift is useful when to want to MULTIPLY an integer (not floating point
numbers) by a power of 2. The operator, like many others, takes 2 operands like this:

a << b

This expression returns the value of a multiplied by 2 to the power of b.
Bitwise Right-Shift does the opposite, and takes away bits on the right. Suppose we had:

a >> b

This expression returns the value of a divided by 2 to the power of b.

Applications of Bitwise operators

Bitwise operators have two main applications. The first is using them to combine several
values into a single variable. Suppose you have a series of flag variables which will
always have only one of two values: 0 or 1 (this could also be true or false). The smallest
unit of memory you can allocate to a variable is a byte, which is eight bits. But why
assign each of your flags eight bits, when each one only needs one bit? Using bitwise
operators allows you to combine data in this way.

Example -- Convert to binary with bit operators

This program reads integers and prints them in binary, using the shift and "and" operators
to extract the relevant bits.
// Print binary representation of integers
#include <iostream>
//using namespace std;
void main() {
int n;
while (cin >> n) {
cout << "decimal: " << n << endl;
// print binary with leading zeros
cout << "binary : ";
for (int i=31; i>=0; i--) {
int bit = ((n >> i) & 1)
cout << bit;
}
cout << endl;
Bitwise Operators and Macros 4
}//end loop
}

Problems

Here are some modifications that could be made to this code.
1. It's difficult to read long sequences of digits. It's common to put a space after
every 4 digits.
2. Suppress leading zeros. This is done most easily by defining a bool flag, setting it
to false at the beginning of each conversion, setting it to true when a non-zero bit
is encountered, and printing zeros only when this flag is set to true. Then there's
the case of all zeros that requires another test.

Typedef

A typedef declaration lets you define your own identifiers that can be used in place of
type specifiers such as int, float, and double. The names you define using typedef are
NOT new data types. They are synonyms for the data types or combinations of data types
they represent.
A typedef declaration does not reserve storage. When an object is defined using a
typedef identifier, the properties of the defined object are exactly the same as if the
object were defined by explicitly listing the data type associated with the identifier.
The following statements declare LENGTH as a synonym for int, then use this typedefto declare length, width, and height as integral variables.
typedef int LENGTH;
LENGTH length, width, height;
The following declarations are equivalent to the above declaration:
int length, width, height;
Similarly, you can use typedef to define a struct type. For example:
typedef struct {
int scruples;
int drams;
int grains;
} WEIGHT;
Bitwise Operators and Macros 5
The structure WEIGHT can then be used in the following declarations:
WEIGHT chicken, cow, horse, whale;
The proposed feature is intended to be a natural application of existing template syntax to
the existing typedef keyword. Interactions with the rest of the language are limited
because typedef templates do not create a new type or extend the type system in any
way; they only create synonyms for other types.

Macros

A macro is a fragment of code which has been given a name. Whenever the name is used,
it is replaced by the contents of the macro. There are two kinds of macros. They differ
mostly in what they look like when they are used. Object-like macros resemble data
objects when used, function-like macros resemble function calls.
You may define any valid identifier as a macro, even if it is a C keyword. The
preprocessor does not know anything about keywords. This can be useful if you wish to
hide a keyword such as const from an older compiler that does not understand it.
However, the preprocessor operator defined can never be defined as a macro, and C++'s
named operators cannot be macros when you are compiling C++.

Macro Arguments

Function-like macros can take
arguments, just like true functions. To define a macro that
uses arguments, you insert parameters between the pair of parentheses in the macro
definition that make the macro function-like. The parameters must be valid C identifiers,
separated by commas and optionally whitespace.
To invoke a macro that takes arguments, you write the name of the macro followed by a
list of actual arguments in parentheses, separated by commas. The invocation of the
macro need not be restricted to a single logical line--it can cross as many lines in the
source file as you wish. The number of arguments you give must match the number of
parameters in the macro definition. When the macro is expanded, each use of a parameter
in its body is replaced by the tokens of the corresponding argument. (You need not use all
of the parameters in the macro body.)
As an example, here is a macro that computes the minimum of two numeric values, as it
is defined in many C programs, and some uses.
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
x = min(a, b); ==> x = ((a) < (b) ? (a) : (b));
y = min(1, 2); ==> y = ((1) < (2) ? (1) : (2));
z = min(a + 28, *p); ==> z = ((a + 28) < (*p) ? (a + 28) : (*p));
Bitwise Operators and Macros 6

Typecasting

Typecasting is making a variable of one type, act like another type for one single
application. To typecast something, simply put the type of variable you want the actual
variable to act as inside parentheses in front of the actual variable. For example (char)a
will make 'a' function as a char.

Types of Typecasting

There are two types of typecasting:
• Implicit typecasting
• Explicit typecasting (
coercion)
Implicit typecasting is done by the compiler itself while the explicit typecasting is done
by us, the developers.
Implicit type casting (coercion) is further divided in two types
• Promotion
• Demotion

Example:

#include <iostream.h>
int main()
{
cout<<(char)65;
//The (char) is a typecast, telling the computer to
//interpret the 65 as alphabet’s first letter “A”
//character, not as a number. It is going to give the
//ASCII output of the equivalent of the number 65(It
should //be the letter A).
return 0;
}
One use for typecasting for is when you want to use the ASCII characters. For example,
assume that we want to create our own chart of all 256 ASCII characters. To do this, we
will need to use to typecast to allow us to print out the integer as its character equivalent.
#include <iostream.h>
int main()
{
for(int x=0; x<256; x++)
{ //The ASCII character set is from 0 to 255
cout<<x<<". "<<(char)x<<" ";
Bitwise Operators and Macros 7
//Note the use of the int version of x to
//output a number and the use of (char) to
// typecast the x into a character
//which outputs the ASCII character that
//corresponds to the current number
}
return 0;
}

Assertions

An assertion statement specifies a condition at some particular point in your program. An
assertion specifies that a program satisfies certain conditions at particular points in its
execution. There are three types of assertion:
Preconditions
• Specify conditions at the start of a function.
Post conditions
• Specify conditions at the end of a function.
Invariants
• Specify conditions over a defined region of a program.
An assertion violation indicates a bug in the program. Thus, assertions are an effective
means of improving the reliability of programs. In other words, they are a systematic
debugging tool.

Assertions and error-checking

It is important to distinguish between program errors and run- time errors:
1. A program error is a bug, and should never occur.
2. A run-time error can validly occur at any time during program execution.
Assertions are not a mechanism for handling run-time errors. For example, an assertion
violation caused by the user inadvertently entering a negative number when a positive
number is expected is poor program design. Cases like this must be handled by
appropriate error-checking and recovery code (such as requesting another input), not by
assertions.
Realistically, of course, programs of any reasonable size do have bugs, which appear at
run-time. Exactly what conditions are to be checked by assertions and what by run-time
error- checking code is a design issue. Assertions are very effective in reusable libraries,
for example, since i) the is small enough for it to be possible to guarantee bug-free
operation, and ii) the routines cannot perform error- handling because they do not
know in what environment they will be used. At higher levels of a program, where
operation is more complex, run-time error-checking must be designed into the code.
Bitwise Operators and Macros 8

Turning assertions off

By default, ANSI C compilers generate code to check assertions at run-time. Assertionchecking
can be turned off by defining the NDEBUG flag to your compiler, either by
inserting
#define NDEBUG
in a header file such as stdhdr.h, or by calling your compiler with the -dNDEBUG option:
cc -dNDEBUG ...
This should be done only you are confident that your program is operating correctly, and
only if program run-time is a pressing concern.

The switch and case keywords

The switch-case statement is a multi-way decision statement. Unlike the multiple
decisions statement that can be created using if-else, the switch statement evaluates the
conditional expression and tests it against numerous constant values. The branch
corresponding to the value that the expression matches is taken during execution.
The value of the expressions in a switch-case statement must be an (integer, char, short,
long), etc. Float and double are not allowed. The syntax is :
switch( expression )
{
case constant-expression1: statements1;
[case constant-expression2: statements2;]
[case constant-expression3: statements3;]
[default : statements4;]
}
The case statements and the default statement can occur in any order in the switch statement. The default clause is an optional clause that is matched if none of the
constants in the case statements can be matched.
Consider the example shown below:
switch( Grade )
{
case 'A' : printf( "Excellent" );
case 'B' : printf( "Good" );
case 'C' : printf( "OK" );
case 'D' : printf( "Mmmmm...." );
Bitwise Operators and Macros 9
case 'F' : printf( "You must do better than this" );
default : printf( "What is your grade anyway?" );
}
Here, if the Grade is 'A' then the output will be
Excellent
Good
OK
Mmmmm....
You must do better than this
What is your grade anyway?
This is because, in the 'C' switch statement, execution continues on into the next case
clause if it is not explicitly specified that the execution should exit the switch statement.
The correct statement would be:
switch( Grade )
{
case 'A' : printf( "Excellent" );
break;
case 'B' : printf( "Good" );
break;
case 'C' : printf( "OK" );
break;
case 'D' : printf( "Mmmmm...." );
break;
case 'F' : printf( "You must do better than this" );
break;
default : printf( "What is your grade anyway?" );
break;
}
Although the break in the default clause (or in general, after the last clause) is not
necessary, it is good programming practice to put it in anyway.
An example where it is better to allow the execution to continue into the next case statement:
Bitwise Operators and Macros 10
char Ch;
.
.
switch( Ch )
{
/* Handle lower-case characters */
case 'a' :
case 'b' :
.
.
.
case 'z' :
printf( "%c is a lower-case character.\n", Ch );
printf( "Its upper-case is %c.\n" toupper(Ch) );
break;
/* Handle upper-case characters */
case 'A' :
case 'B' :
.
.
.
case 'Z' :
printf( "%c is a upper-case character.\n", Ch );
printf( "Its lower-case is %c.\n" tolower(Ch) );
break;
/* Handle digits and special
characters */
default :
printf( "%c is not in the alphabet.\n", Ch );
break;
}
..

Tips

Take extreme care while using the Bitwise operators as these operates on
individual bits.
Bitwise Left Shift << operator is useful when we to want to multiply an integer by
a power of two.
Bitwise Operators and Macros 11
Bitwise Right Shift >> operator is useful when we to want to divide an integer by
a power of two.
Do remember that when an object is defined using a typedef identifier, the
properties of the defined object are exactly the same as if the object were defined
by explicitly listing the data type associated with the identifier.
To invoke a macro that takes arguments, you write the name of the macro
followed by a list of actual arguments in parentheses, separated by commas.
Any type-casting done by us is considered to be the explicit type casting. Implicit
typecasting is always done by the compiler
Do remember that when we use typecasting, then the data type of one variable is
temporarily changed, while the original data type remains the same
Assertions are an effective means of improving the reliability of programs. They
are a systematic debugging tool.
The value of the expressions in a switch-case statement must be an (integer, char,
short, long), etc. Float and double are not allowed.

Summary

In this lecture, we have learned about the three major bitwise operators AND, OR, XOR.
Bitwise operators operates on individual bits.
Using “typedefs” provide an easy way to avoid the long names during the declarations
and thus make our code more simple. We have also discussed about the typecasting. It is
making a variable of one type, act like another type for one single application. The two
types of type casting includes the implicit type casting and the explicit type casting.
In C, the assertions are implemented with standard assert macro, the argument to assert
must be true when the macro is executed, otherwise the programmes aborts and printouts
an error message.
The switch-case statement is a multi-way decision statement. Unlike the multiple
decisions statement that can be created using if-else, the switch statement evaluates the

conditional expression and tests it against numerous constant values.

<Previous Lesson

Visual Programming

Next Lesson>

Home

Lesson Plan

Topics

Go to Top

Next Lesson
Previous Lesson
Lesson Plan
Topics
Home
Go to Top