The best programs are written so that computing machines can perform them quickly and so that human beings can understand them clearly. A programmer is ideally an essayist who works with traditional aesthetic and literary forms as
well as mathematical concepts, to communicate the way that an algorithm works and to convince a reader that the results will be correct. Donald E. Knuth

C++ Preprocessor

Preprocessor directives begin with # symbol and they give instruction to the compiler to preprocess a piece of code before actual compilation starts.

File Inclusion
So far, we have been using preprocessors to include header files for e.g. #include < iostream >. A C++ program may consist of multiple files and we can include the contents of one file into another using the preprocessor directive. Suppose we have a file which contains a function to compute the factorial of a number. We can include this file in any other C++ file to get the factorial.
Consider the program below :

/*
 * File : factorial.cpp
 * Compute the factorial of a number
 * factorial(n) is denoted by n!
 * n! = n x (n-1) x (n-2) x ... x 2 x 1
 * For e.g. 5! = 5 x 4 x 3 x 2 x 1 = 120
 */

int factorial(int n) {
   int fact = 1, i;
   for (i = n; i >= 1; i--) {
      fact *= i;
   }
   return fact;
}
/*
 * File : series.cpp
 * This function computes the sum of the series for n terms :
 * 1 + ( x^1 / !1 ) + ( x^2 / 2! ) + ( x^3 / 3! ) + ... + ( x^(n-1) / (n-1)! )
 * if x = 2 and n = 5
 * sum = 1 + (2^1 / 1!) + (2^2 / 2!) + (2^3 / 3!) + (2^4 / 4!)
 *     = 1 + 2 + 2 + 1.33 + 0.67 = 6.99
 */

#include <iostream>
#include "cmath"
#include "factorial.cpp"
using namespace std;

float series(int x, int n) {
   int i;
   float sum = 1.0; // first term is always 1
   // start iterating from 2nd term
   for (i = 1; i < n; i++) {
      int numerator = pow(x, i); // compute x^i
      int denominator = factorial(i);
      sum += (float)numerator / denominator;
   }
   return sum;
}

int main() {
   int x, n;
   float sum;
   cout << "Enter the value of x : ";
   cin >> x;
   cout << "Enter no. of terms of the series : ";
   cin >> n;
   sum = series(x, n);
   cout << "Sum of the series for " << n << " terms is " << sum << endl;
   return 0;
}
Run this program in your system to include above file  

Please note that, no matter how many files are there in a program, main( ) can be present in one file only.
We have used " " instead of < > because factorial.cpp is not a part of any library. It is present in the current directory. We can use " " for including iostream and other header files also. If we use < >, compiler doesn't search for that file in current directory.
File inclusion is one use of preprocessors which includes one file into another before compilation starts. Let's explore some other uses of preprocessor directives.

Macros
We can create symbolic constants called macros using #define preprocessor directive. if we declare a statement like #define PI 3.14, then every occurrence of PI in the program is replaced by the value 3.14 before the compilation starts. Macros can also take arguments similar to functions and they can extend over multiple lines also. Following program illustrates the use of macros :

#include<iostream>
using namespace std;

#define PI 3.14   // symbolic constant

#define SQUARE(x) (x * x) // macro taking argument

/* macro extending over multiple lines */
#define MAXIMUM(a, b) { \
          		if ( a > b) \
         		   cout << a; \
          		else \
         	       cout << b; } 

int main() {
   float r1 = 6.0, r2 = 7.0;
   float area1 = PI * SQUARE(r1); // calculate area of circle
   float area2 = PI * SQUARE(r2);
   cout << "Area of circle 1 : " << area1 << endl;
   cout << "Area of circle 2 : " << area2 << endl;
   cout << "Maximum Area is ";
   MAXIMUM((int)area1, (int)area2); // print maximum area
   cout << endl;
   return 0;
}

The ' \ ' symbol is used to extend macro definition to multiple lines.
We can see that the macros SQUARE( x ) and MAXIMUM( a, b ) behave like functions. The difference is that MACRO calls are replaced by MACRO definitions by the compiler whereas in case of functions, control is transferred to the function definition whenever a function is called.

Conditional Compilation
Consider a scenario in which some part of code is architecture specific i.e we need to write different codes for the same function for different architectures. Support we are using INTEL based machine, then we should not compile the code which which is meant for MOTOROLA machines. This kind of conditional compilation is achieved using #define preprocessor directives. Following example illustrates this :

void func() {
   #ifdef INTEL
       /* Code specific to INTEL Architecture */
   #elif MOTOROLA
       /* Code specific to MOTOROLA Architecture */
   #else
       /* Code specific to other Architectures */
   #endif
}

If the statement #define INTEL is present, then the code corresponding to INTEL architecture is compiled and executed. An important use case of conditional compilation is enable or disable debugging statements in a program. See the program below to understand this feature :

#include<iostream>
#define DEBUG
using namespace std;

int main() {
   int i, sum = 0;
   for (i = 1; i <= 10; i++) {
      sum += i;
   #ifdef DEBUG
      cout << "Current Sum : " << sum << endl;
   #endif
   }
   cout << "Sum : " << sum << endl;
   return 0;
}

We see that the macro DEBUG is defined, so the debug statement is printed every time. To disable this, just comment out the line where DEBUG is defined. We can completely comment out a piece of code using #if 0 statement.


#if 0
   /* This piece of code is not compiled */
#endif
Run this program in your system to take input at run-time  

Back | Next