A Detailed Look At Preprocessor Directives In C++.
The preprocessor is a unique feature of C++. In C++, we have steps like compilation, linking and execution for a typical program. In reality, we have a lot of other features in a C++ program that needs to be processed before passing the program for compilation.
For this purpose, a special step called preprocessing is carried out. Preprocessing is carried out before the compilation process and the special features are preprocessed. As a result, an expanded C++ program is obtained and then it is passed to the compiler.
=> Visit Here To Learn C++ From Scratch.
Table of Contents:
Overview
The special features for preprocessing are identified using an entity called “Preprocessor directive”. These preprocessor directives tell the compiler that certain information in the C++ program marked with preprocessor directives need to be preprocessed before compilation.
Note that in C++ all preprocessor directives begin with a “#” symbol. The moment the preprocessor (part of the compiler) encounters the # symbol, the information following the # symbol is preprocessed before passing the program to the compiler.
Unlike the other C++ statements, preprocessor directives do not end with a semicolon.
In this tutorial, we will explore the various preprocessor directives supported by C++.
File Inclusion Directives
#include
File inclusion directive #include allows us to include other files in our source program. We can include any header file that contains definitions of various predefined functions in our program using these functions. We can include header files in our program using the following syntax.
#include <filename>
Example:#include <iostream>
We have already seen this in our C++ programs. The header iostream contains the functions required for input/output data streaming like cout, cin, etc.
As our programs grow larger or the functionality becomes complex, we might want to divide our program into various files or import functionality from the other files. In this case, we make use of user-defined files. To include user-defined files in our program we can make use of the following syntax of #include directive.
#include “filename”
Example: #include “vector_int.h”
This is a user-defined header file that we intend to include in our program in order to use its functionality.
The below code Example shows the usage of the #include directive.
#include <iostream> using namespace std; int main() { cout<<"This is an example demonstrating inclusion directive #include"; }
Output:
This is an example demonstrating the inclusion directive #include.
As shown, we have used the #include directive to include the functionality of the <iostream> header in our program.
Macro Definition Directives
#define
The #define directive is used to define the symbolic constants or macros in C++ program.
The general form of a #define directive is:
#define macro_name replacement code
When a preprocessor encounters the macro in the program, the preprocessor replaces this macro with the code that is defined using the #define directive before the code is passed to the compiler.
The below code Example shows a symbolic constant RADIUS that is defined using #define directive and its usage in the program.
#include <iostream> #define RADIUS 5 using namespace std; int main() { cout<<"Area of a circle : "<<3.142 * RADIUS * RADIUS; }
Output:
Area of a circle : 78.55
As shown in the program, we can make use of symbolic constant RADIUS in our code and it will be replaced by the value defined for it using the #define directive.
We can use the #define directive to define a proper function code. These functions are usually small functions.
An example is shown below.
#include <iostream> #define REC_AREA(length, breadth) (length * breadth) using namespace std; int main() { int length = 20, breadth = 5, area; area = REC_AREA(length, breadth); cout << "Area of a rectangle is: " << area; return 0; }
Output:
Area of a rectangle is: 100
Here using the #define directive we have defined a function REC_AREA that takes two arguments i.e. length and breadth and calculates the area of a rectangle. In the main function, we just make use of this macro and supply two arguments to it to obtain the area of a rectangle.
#undef
Macros in a program defined with the #define directive last until it is undefined using the #undef directive. Once the program encounters #undef, the subsequent use of macro (undefined by #undef) will give a compilation error.
In the above program, if we just give a statement #undef REC_AREA after the integer declarations, then the program will give a compilation error.
Conditional Compilation Directives
Apart from the directives explained above, C++ also provides the following directives that can be used for conditional compilation of code. These directives can be used on similar lines of the if-else statement of C++.
For Example, we can set DEBUG for a program ON or OFF using these conditional directives.
Some of the conditional compilation directives provided in C++ include:
- #if
- #elif
- #endif
- #ifdef
- #ifndef
- #else
The below program demonstrates the usage of conditional compilation directives in a C++ program.
#include <iostream> using namespace std; #define DEBUG #define MAX(a,b) (((a)>(b)) ? a : b) int main () { int i, j; i = 100; j = 50; #ifdef DEBUG cout <<"Trace: Start of main function" << endl; #endif cout <<"The maximum is " << MAX(i, j) << endl; #undef MAX //cout <<"The maximum is " << MAX(10,20) << endl; #ifdef DEBUG cout <<"Trace: End of main function" << endl; #endif return 0; }
Output:
Trace: Start of main function
The maximum is 100
Trace: End of main function
In the above program, we use #ifdef – #endif directive to define a DEBUG for the program. Then we undefined the macro function MAX using the #undef directive. The conditional compilation directive constructs #ifdef – #endif checks if DEBUG is set and if it’s set, it prints few messages in the program.
The # & ## Operators
The # and ## operators are two special operators that are respectively used to convert a text token into a string to be displayed and concatenate two tokens.
Below given is an Example demonstrating both these operators.
#include <iostream> using namespace std; #define MKSTR( x ) #x #define concat(a, b) a ## b int main () { cout <<"MKSTR(Hello World) = "<< MKSTR(Hello World) << endl; int xy = 100; cout <<"concat(x,y) = "<<concat(x,y); return 0; }
Output:
MKSTR(Hello World) = Hello World
concat(x,y) = 100
In the above program, we define MKSTR with an argument x. It has body #x. When we print this MKSTR using the argument “Hello World”, we see that because of #x, the argument is converted to a string and is displayed to the output.
Next, we have defined a concat function with two arguments a and b. In the body we specify a##b. Expression a##b equals ab. Thus in the main function when we call concat(x,y), it actually evaluates to xy which is equal to the integer variable that we defined.
Other Directives
#error
The general syntax of the #error directive is:
#error error_message
When the compiler encounters #error directive, it displays the error_message and the compilation stops. The argument error_message can contain one or more words with or without quotes.
#line
This tells the compiler to change the compiler’s internally stored line number and filename to the given line number and filename.
#line digit-sequence [“filename”]
The digit_sequence can be an integer constant.
Example: #line 200 test.c
In the above example, the internally stored line number is set to 200 and the filename is changed to test.c.
#pragma
Supplies implementation-defined instructions to the compiler. These instructions are specific to the compiler and the platform. If the instruction does not match, the directive is ignored without generating a syntax error.
Predefined Macros
C++ also defines numerous predefined macros that can be used by the programmers.
Some of these macros are tabularized below.
Predefined Macro | Description |
---|---|
__FILE__ | The current file name of the program being compiled |
__DATE__ | Date of translation of source code into object code in the format month/day/year |
__TIME__ | Time in the form hour:minute:second at which program is compiled |
__LINE__ | The current line number of the program that is being compiled |
__cplusplus | Integer constant that is defined for each compiler version |
The following program demonstrates these macros in a program.
#include <iostream> using namespace std; int main () { cout<<"__LINE__ :" << __LINE__ << endl; cout<<"__FILE__ :" << __FILE__ << endl; cout<<"__DATE__ :" << __DATE__ << endl; cout<<"__TIME__ :" << __TIME__ << endl; cout<<"__cplusplus:"<<__cplusplus<<endl; }
Output:
__LINE__ :5
__FILE__ :prog.cpp
__DATE__ :Apr 15 2019
__TIME__ :12:09:15
__cplusplus:201402
The program output above is in line with the explanation of the predefined macros above and is self-explanatory.
Conclusion
In this tutorial, we have seen various preprocessor directives provided by C++ along with their examples. Preprocessor directives help us write more efficient programs and more readable programs to some extent.
The conditional compilation directives also allow us to branch our program output in various ways.
=> Look For The Entire C++ Training Series Here.