Preprocessors in C Programming

Preprocessors are programs which process the input data and produces an output which is taken as input for another program. In simpler words, it is another program that processes our program and sends it to the compiler.

The compilers rely on this preprocessed data for convenience. The C code that we write is known as the ‘source code’ (Eg: Hello.c) ,the preprocessor processes this source code to produce ‘Expanded Souce Code’ (Eg: Hello.I) which is then compiled by the compiler to give us the output. The C preprocessor  also known as CPP is a macro preprocessor.

It is used to include header files, line control, macro expansions and conditional compilation. In C programming it is mostly used by the compiler at the beginning of the code to include certain functionalities that come with the header files.


Features of the C Preprocessor

The features offered by the C preprocessor are also known as ‘Preprocessor Directives’. These directives are preceded by a ‘#’ symbol. Here we have the following Preprocessor Directives:

  • Macro Expansion
  • File Inclusion
  • Conditional Compilation
  • Other Directives

Macro Expansion

As we already know Preprocessor are the programs which are used before compilation. As a part of the C Preprocessor, macro  serves the same purpose. It is a block of statements used as a Preprocessor Directive. A macro is also known as a macro definition. Let’s have a look at an example to have a clear picture of a macro definition:

#include<stdio.h>
#define NUM 10
int main()
{
  int square;
  square= NUM * NUM;
  printf("The square is %d",square);
  return 0;
}

The macro #define puts the value 10 everywhere NUM is being used in the program. Let’s see what is happening here in detail. Before the program passes on to the compiler it is processed by the Preprocessor for macro definitions. When it finds #define it replaces the macro template with the macro expansions everywhere in the source code and sends it to the compiler.

But an important question that arises over here is why use a macro definition when we can define NUM anywhere inside the main() function? The answer is that when we define NUM with the value 10, it replaces NUM with 10 everywhere in the program. So, in case we need to make any changes to the value of NUM the only thing we need to do is change it in the macro definition and it shall be replaced everywhere in the program, instead of manually changing it everywhere in the program which will be very difficult for complex programs.

You must’ve seen the use of capitals for the macro and wondered why? Macro Templates do not necessarily be written in capitals. It is written in capitals mainly for the programmer’s convenience. It helps to distinguish a simple variable in the code from a macro. A programmer can follow the basic variable norms to define a macro. The following are more uses of the #define directive:

  • It can be used to define operators. Eg: #define OR ||
  • It can be used to replace a condition. Eg:#define TAX (a>2.5 && a<4.5)
  • It can be used to replace a C statement. Eg: #define TRUE printf(“The above statement is true”);

File Inclusion

This feature of C Preprocessor allows a programmer to include other files in the C code. #include is the command used to include another file or header into the program. But the question that arises her is why include files into our code?

This can be done for the following reasons:

  • In the case of a complex program, the different parts of a program can be written in different files and then included in the main program. This reduces the possibility of errors in the code.
  • it helps make our code modular. We write several programs which use a common file or functions or macro definitions then the same file can be included in the program without manually writing the whole function again and again which reduces errors in the code and possible inconvenience.
  • In case we create library functions and make it accessible to others we need to create a filename with a .h extension which can be included in the program with minimal efforts.
  • To include certain inbuilt header files we need this feature of C Preprocessor. (header files explained in detail in the next tutorial)

Conditional Compilation

This Preprocessor directive allows us to include or skip over a part of the source code by using the commands like #ifdef, #ifndef,#if, #elif, #else, #endif. Let’s have a look at the function of these conditional preprocessors:

  • #ifdef        : Results in true if preprocessor macro is defined.
  • #ifndef     : Results in true if preprocessor macro is not defined.
  • #if              : Results in true if the block of statements is true.
  • #elif           : Stands for ‘else if’.
  • #else          : Alternative for the #if block of statements.
  • #endif       : Ends the #if block of statement.

Here’s an example :

#include <stdio.h>
#include <stdlib.h>
#define NUM 10
int main()
{
  int square, cube;
  #ifdef NUM
  square=NUM*NUM;
  printf("square is: %d",square);
  #else
  cube=NUM*NUM*NUM;
  printf("Cube is: %d",cube);
  #endif // NUM
  return 0;
}

Output:-

square is: 100

In this code we get the output as above because we have defined NUM at the beginning of the code. So, the #ifdef statement returns true and the block of statements under #ifdef gets executed.

In case we have other condition for the compilation of the code which evaluates to true, we use the #if preprocessor. The following example illustrates this :

#include <stdio.h>
#include <stdlib.h>
#define NUM 10
int main()
{
  int square, cube;
  #if NUM>10
  square=NUM*NUM;
  printf("square is: %d",square);
  #else
  cube=NUM*NUM*NUM;
  printf("Cube is: %d",cube);
  #endif 
  return 0;
}

Output:-

cube is: 1000

Here the #if condition returns false and hence the block of statements under #else is executed.


Other Directives

The other preeprocessor directive available in C are:

  • #undef     : It is used to undefine a preprocessor macro. Eg: #undef NUM 10
  • #error      : Used to output an error message. Eg: #error “the error statement to be put here”
  • #pragma : Used to instruct the compiler to use pragmatic or implementation-dependent features. It issues special commands to the compiler. They may differ for different compilers. Let’s have a look at the different #pragmas available for C:

The #Pragma Directive

  • #pragma startup and #pragma exit: The #pragma startup directive allows us to call upon any function at the beginning, i.e., before the main() function. The #pragma exit directive allows us to call upon any function at the end of compilation,i.e., before termination . Eg: #pragma startup func1
  • #pragma warn: This directive is used to turn on/off the warnings generated by the compiler. The ‘+’ before the warning turns the warning on, the ‘-‘ turns warning off and the ‘.’ sign toggles it. Eg: #pragma warn -par /*parameter not used*/

The ‘#’ operator

Wondering why we use ‘#’ before every preprocessor? Here’s your answer

‘#’ is the stringizing operator. In proper words, it coverts the macro preprocessor to string literals or text tokens.It is mostly used by macros with parameters or arguments. It is used to substitute macro parameters into macro body. The parameter shall be turned into a string ,i.e., enclosed within double quotes. The white spaces preceding the first token and following the last token shall be eliminated. More than one space between the tokens shall be considered as a single white space. Also if a comment line exists between the token it shall be reduced to a single space.

Below is an example of stringizing operator. Please try to understand it yourself and try it and believe me it will help you in better understanding. Still have some questions then do not forget to comment.

#include <stdio.h>

#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)

#define STR "Hello! Welcome to "
#define DOMAIN Codingeek
#define S_DOMAIN STRINGIFY(DOMAIN)
#define WELCOME_MSG STR S_DOMAIN

int main() {
	
	//When we actually pass some value
	printf("%s",STRINGIFY(Hello));
	
	// When it is pre calculated
	printf("\n%s",WELCOME_MSG);
	return 0;
}

Output:-
Hello
Hello! Welcome to Codingeek

An investment in knowledge always pays the best interest. Hope you like the tutorial. Do come back for more because learning paves way for a better understanding.

Do not forget to share and Subscribe.

Happy coding!! :)