INFORMATION FROM DR. EBRAHIMI'S C++ PROGRAMING EASY WAYS

Home                  ABOUT US                    CONTACT US                  TUTORIAL

CHAPTER 20

 

POTPOURRI (MIXED BAG)

 

 

While wrapping up this book, I found there were many concepts and topics that should have been introduced in earlier chapters but did not fit into a single chapter. These topics are introduced here as a mixed bag with a variety of flavors. Also, I want to congratulate you for getting this far and covering the many chapters. Obviously you have obtained a unique and worthwhile experience. You should be proud and put into use what you have learned. In my own experience, I have found that repetition is the key to my own learning, whether learning a programming language or a natural language like Spanish or even Chinese. 

 

 

BIT-WISE OPERATIONS

 

One power of C/C++ is the ability to perform low-level operations that are done by machine languages. These operations are performed on bits. Recall, numbers and addresses are represented in binary form internally. In many applications, especially hardware, it is desirable to work with these bits. The language of C/C++ is known as a language that works closely with hardware. Because of the importance of bit-wise operations, C/C++ chooses to use one key strike for bit-wise operators (&, |) and two strikes for the logical operators (&&, ||). The following symbols are used for the C/C++ bit-wise operations.

 

|           bit-wise or operator

&         bit-wise and operator

^          bit-wise exclusive or operator

<<        shift left operator

>>        shift right operator

~          bit complement (unary operator)

 

 

BIT-WISE OPERATIONS: EXAMPLES

 

The general form of the bit-wise or operation is variable1  | variable2 where each variable of type integer is converted to binary (bits). The bit-wise or operation of two bits is zero if both corresponding bits are zero (0), otherwise the resulting bit is one (1).

 

The general form of the bit-wise and (&) is variable1 & variable2, where each variable of type integer is converted to binary. The bit-wise and operation of two bits is one if the two corresponding bits have values of 1, otherwise the resulting bit is zero.

 

The general form of the bit-wise exclusive or (^) operation is variable1 ^ variable2, where both variables and resulting variable are of type integer and are converted to binary. The exclusive or of two bits is zero if the two bits are the same, otherwise it is one. The exclusive or is different from the bit-wise or in that the exclusive or of two bits with values 1 results to zero.

 

The & operator is often used to mask off certain bits, e.g. value & 1111111. The result sets all of the bits of the value to zero except the first 8 bits (low-order).  

 

In the following program, the binary representation for 3 is 011 and 5 is 101. The resulting bit-wise or is 111 which is 7, the resulting bit-wise and is 001 which is 1, and the resulting exclusive or is 110 which is 6.

Text Box: #include <iostream>
using namespace std;
int main(){
                int x,y,z;
                x=3; y=5;
                z=x | y;
                cout<<" BITWISE | OF TWO  VALUES IS:"<<z<<endl;
                z=x & y; 
                cout<<" BITWISE & OF TWO  VALUES IS:"<<z<<endl;
                z=x ^ y;
                cout<<" BITWISE ^ OF TWO  VALUES IS:"<<z<<endl;
              return 0;   
}//MAIN

  

 

 

 

 

 

 

 

 

 

 

 

 


 

   Figure 20.1a - Program to demonstrate the bit-wise operators

 

Text Box:  BITWISE | OF TWO  VALUES IS:7
 BITWISE & OF TWO  VALUES IS:1
 BITWISE ^ OF TWO  VALUES IS:6

  

 

 

 


 

   Figure 20.1b - Output of Figure 20.1a

 

 

BIT-WISE SHIFTS: SHIFT LEFT <<, SHIFT RIGHT >>

The general form of the shift left operator is variable << n, where n is the number bits to be left shifted. As the bits are shifted left, a zero bit fills the shifted position (zero left padding). After each left shift, a 0 is added next to the least-significant bit of the binary number, which makes the number twice as large (multiply by 2). Similarly, the general form of right shift is variable >> n, where n is the number of bits to be right shifted. As the bits are right shifted, the shifted position (high-order bit) is filled with zero (zero right padding). After each right shift, the binary number looses the right bit, which is the same as dividing the number by 2. As an exercise try to shift left a negative number, including –1, or use the rotate operation to perform a circular shift by moving the lost bit to the other side. In the following program the value of 4 is left shifted by 2, resulting in a value of 16 and the value of 16 is right shifted by 1, resulting in a value of 8.

 

Additionally note that the left shift and right shift operators are overloaded in C++ for input and output, and are known as extraction and insertion (cin>>   ,  cout <<).

Text Box: #include<iostream> 
using namespace std;
int main(){
                int x =4;
                x= x << 2;
                cout<<" VALUE OF X AFTER LEFT SHIFT:"<<x<<endl;
                x = x >> 1;
                cout<<" VALUE OF X AFTER RIGHT SHIFT:"<<x<<endl;
               return 0;  }//MAIN

  

 

 

 

 

 

 

 


 

  Figure 20.2a - Program using bit-wise shift left and shift right

Text Box: VALUE OF X AFTER LEFT SHIFT:16
VALUE OF X AFTER RIGHT SHIFT:8

  

 

 


 

                                                                                                         

  Figure 20.2b - Output of Figure 20.2a

 

COMPLEMENT OPERATOR ~
Text Box: #include<iostream>
using namespace std;
int main(){
int x=1, y=~x;
cout<<"       "<<hex<<x<<endl;
cout<<hex<<y<<endl; 
cout<<hex<<x+y<<endl;
return 0;
}//MAIN
 
 
 
 
 
 
The form of the complement operator is ~variable, where a binary bit is converted to its opposite is also known as 1’s complement using the unary operator ~ ( tild ). For example, the complement of 1 is 0 and the complement of 0 is 1. A variable of type integer is converted to its binary form and complement is applied to it.

 

 

 

 

 

 

 

 

 

 

Text Box:          1
fffffffe
ffffffff
 
Text Box: Figure 20.3a – Program to demonstrate the complement operator
 

  

 

 

 

 


 

 

Text Box: Figure 20.3b – Output of Figure 20.3a
 

  

 


 

SWAP FUNCTION USING EXCLUSIVE OR

 

If you are wondering what you can do with the bit-wise operators, here is an example that uses exclusive or to swap two values without introducing a temp variable so the program uses less memory. There are other tricks that can be done using the bit-wise operations to do certain things in an unordinary way. For example: performing multiplication by using shift left, division by using shift right, and subtraction by addition of the 2’s complement. As an exercise, encrypt/decrypt a file using an exclusive or (^). You may want to exclusive or each character with a selected ASCII character.

Text Box: #include<iostream>
using namespace std;
void swap(int &x, int &y){
            y=x^y;
            x=x^y;
            y=x^y;}//SWAP
            
int main(){
            int x=5, y=6;
            cout<<"BEFORE: "<<x<<"   "<<y<<endl;
            swap(x,y);
            cout<<"AFTER:    "<<x<<"   "<<y<<endl;
            return 0;
}//MAIN
 
 
 

  

 

 

 

 

 

 

 

 

 

 

 

 

 


 

  Figure 20.4a – Program using exclusive or to swap two values

 

Text Box: BEFORE: 5   6
AFTER:   6   5

  

 

 

 


 

  Figure 20.4b – Output of Figure 20.4a

 

 

COMMAND LINE ARGUMENTS

 

Until now you may have wondered why in C/C++ in the main( ) we use open and close parentheses without anything inside the parentheses. Now is time to give the reason for it. One rationale for using parentheses is that the main program is a function and therefore, it can have parameters (arguments). For example, void main( ) is a function that does not take any parameters (argument-less) and returns nothing. However, a main program can have general parameters such as int main( int argc, char* argv[ ]). This main function has two special arguments, one known as argument counter (argc) which counts the number of arguments, and argument vectors (argv[ ]) which is an array of pointers to each argument. Automatically, these arguments are set and as a programmer you can use them to your advantage.

 

 

HOW THE MAIN PROGRAM IS CALLED

 

The main program is called from the operating system environment using a command prompt (DOS or UNIX prompt). The executable file name of the main program can be used to pass the parameters. For example, copy fileA fileB to fileC. The copy command calls an executable file known as copy.exe (generated from copy.cpp) with five arguments (argc is 5 including the file name). argv[0] is pointing to copy, argv[1] points to fileA, argv[2] points to fileB, argv[3] points to the word to, and argv[4] points to fileC. It is the programmer’s job to handle these arguments (words) and treat them as intended, whether they are a file or other information. You can understand how a system programmer has built the system commands by understanding the command line arguments. In fact you can make them friendlier and customize them to suit your own taste.

 

 

SYSTEM PROGRAMMING

 

One job of a system programmer is to build the commands that become the interface between the user (operating system) and the computer while carrying out the request of the user and utilizing the computer’s resources. For example, in UNIX the command           cp fileA  fileB copies the contents of fileA to fileB. Similarly, in DOS, the prompt copy fileA fileB does the same job. A system programmer can even make the above commands friendlier by inserting the word “to” between the source file and the destination file: copy fileA to fileB. If you understand the command line arguments, then you can build your own commands and customize them. You can make your own command-line calculator (e.g. add 2 + 3) or you can create generic searches (e.g. search tel Ebrahimi). The following program demonstrates a sample command line program for a copy command:

Text Box: #include<iostream>
#include<fstream>
using namespace std;
int main(int argc, char* argv[]){
        if(argc<4)
                cout<<"TOO FEW PARAMETERS";
        else{
        ifstream fin(argv[1],ios::in);
        ofstream fout(argv[3],ios::out);
        char c;
        while(fin>>c){
        fout<<c;}//WHILE
        fout.close();
        fin.close(); }//ELSE
        return 0;
}//MAIN

  

 

 

 

 

 

 

 

 


 

 

Figure 20.5a – Program demonstrating command-line arguments

Text Box: copy fileA to fileB

  


 

               

    Figure 20.5b – Output of Figure 20.5a

                       

 

Text Box: ABCDEF

Text Box: ABCDEF

                  

 

 

   Figure 20.5c -  fileA                   Figure 20.5d -  fileB

           

 

 

 

This program copies the contents of one file, character by character, to another file. The above program is named copy.cpp. To create the copy command, you must compile the program with the line g++ -o copy copy.cpp; this sends the executable code to the copy command. To run this copy program, at the prompt type: copy fileA to fileB.

 

 

RUN TIME TYPE ID (RTTI)

 

In C++, the run time type information feature is supported by the typeid operator, which determines the type of a variable during run time. To use this feature you must include the header #include <typeinfo>.

 

With the use of the typeid operator, two objects can be compared to determine if they are of the same type or not. One reason to use typeid is to figure out the type of object during run time and cast (convert) it if necessary.  

Text Box: #include<typeinfo>
#include <iostream>
using namespace std;
int main(){
            double pi=3.14159;
            cout<<"TYPE OF VARIABLE IS: "<<typeid(pi).name()<<endl;
            if(typeid(pi).name() == typeid(double).name())
                        cout<<"THEY ARE SAME TYPE"<<endl;
            return 0;
}//MAIN

  

 

 

 

 

 

 

 

 

 

 


 

   Figure 20.6a – Program using the typeid operator

 

Text Box: TYPE OF VARIABLE IS: double
THEY ARE SAME TYPE

  

 

 


 

   Figure 20.6b – Output of Figure 20.6a

 

 

TYPE CONVERSION: CASTING, DYNAMIC CASTING, REINTERPRET

 

A type can be converted legally, implicitly or explicitly, to another type. A type can be converted implicitly through assignment, one type to another, as long as the smaller type is assigned to the larger type to avoid loss of precision. A type can be converted explicitly by the use of an operator, known as a cast operator. The general form is  (type) variable.

For example, the function sqrt( x ) takes double as its argument, therefore for an integer value, it is necessary to convert the int type to double by casting it with the following: sqrt( (double) x). Note that the value of the variable is passed as a double, but the value of variable x does not change.

 

Other than the C-style type casting, there are four more casting techniques in C++. In addition to casting the basic data types, the pointer type and user-defined types (classes) can be cast. The four different castings have a similar form:

static_cast <newtype> (expression) and are explained below.

 

reinterpret_cast: is mainly used for casting with a pointer, such as casting one pointer type to another pointer type or a pointer type to a non-pointer (e.g. int) type or vice versa.

static_cast: is like C-style casting  e.g. converting double to int.

const_cast: is for constant casting and takes away the const casting.

dynamic_cast: inspects the variable (object) type at run time and returns a valid pointer if the object is of the expected type or a null pointer if the object is not of the expected type. The dynamic _cast is mainly used in situations where the correctness of the type conversion cannot be determined during compile time.

 

Hosted by www.Geocities.ws

1