Preprocessor Directives in C Programming

The C Preprocessor is not part of the compiler but it extends the power of C programming language. All preprocessor directives begin with a # symbol.

The preprocessor step comes before compilation of source code and it instruct the compiler to do required pre-processing before actual compilation.

Points to Remember about Preprocessor Directives
  • Preprocessor directives are processed before compilation of source code.
  • All preprocessor directives begin with a # symbol.
  • Preprocessor directives do not ends with semicolon.
C Preprocessor Directives Workflow
Types of Preprocessor Directives
  • Macro Substitution
  • Conditional Compilation
  • File Inclusive
Below is the list of Preprocessor Directives
Directive Description
#include It includes header file inside a C Program.
#define It is substitution macro. It substitute a constant with an expression.
#if It include a block of code depending upon the result of conditional expression.
#else It is complement of #if
#elif #else and #if in one statement. It is similar to else if ladder.
#endif It flags the end of conditional directives like #if, #elif etc.
#undef Undefines a preprocessor macro.
#ifdef Returns true If constant is defined earlier using #define.
#ifndef Returns true If constant is not defined earlier using #define.
#pragma Issues special commands to the compiler.
#error Prints error message on stderr.

#include Preprocessor Directives

#inclide Preprocessor Directives is used to include header file inside C Program. It checks for header file in current directory, If path is not mentioned. To include user defined header file we use double quote instead of using triangular bracket.

For Example
#include           // Standard Header File
#include "myHeaderFile.h"    // User Defined Header File

First line tells the preprocessor to replace this line with content of string.h header file.
Second line tells the preprocessor to get myHeaderFile.h from the current directory and add the content of myHeaderFile.h file.


#define Preprocessor Directives

It is simple substitution macro. It substitute all occurrences of the constant and replace them with a expression.

#define identifier value
  • #define : It is preprocessor directive used for text substitution.

  • identifier : It is an identifier used in program which will be replaced by value.

  • value : This is the value to be substituted for identifier.

For Example
#define PIE 3.141
#define ZERO 0

C Program to show use of #define Preprocessor Directives
#include <stdio.h>

#define PI 3.141

int main(){
    int radius;
    float circumference;
    printf("Enter the radius of circle\n");
    scanf("%d", &radius);
    
    circumference = 2*PI*radius;
    
    printf("Circumference of Circle = %f", circumference);
    
    return 0;
}

Output
Enter the radius of circle
5
Circumference of Circle = 31.410000

#define macro substitution with arguments

#define Preprocessing directive can be used to write macro definitions with parameters.

  • Whenever a macro identifier is encountered, the arguments are substituted by the actual arguments from the c program.
  • No data type defined for macro arguments. You can pass any numeric like int, float etc.
  • Argument macro is not case sensitive.
For Example
#define circumference(r) (2*3.141*(r))

C Program to show Macro Substitution with Arguments

#include <stdio.h>

#define circumference(r) (2*3.141*(r))

int main(){
    int radius;
    float c;
    printf("Enter the radius of circle\n");
    scanf("%d", &radius);
    
    c = circumference(radius);
    
    printf("Circumference of Circle = %f", c);
    
    return 0;
}

Output
Enter the radius of circle
5
Circumference of Circle = 31.410000
#if, #else and #endif Conditional Compilation Preprocessor Directives

The Conditional Compilation Directives allow us to include a block of code based on the result of conditional expression.

#if Condition_Expression
    statements;
#else
    statements;
#endif
It is similar to if else condition but before compilation.
Condition_Expression must be only constant expression.

C program to show Conditional Compilation using #if, #else and #endif

#include <stdio.h>

#define COUNT 5

void main(){
   #if(COUNT > 1)
       printf("Enter %d numbers\n", COUNT);
   #else
       printf("Enter a number\n");
   #endif

   return 0;
}

Output
Enter 5 numbers

Predefined Macros in C Language

C Programming language defines a number of macros. Below is the list of some commonly used macros.

Macro Description
NULL Value of a null pointer constant.
EXIT_SUCCESS Value for the exit function to return in case of successful completion of program.
EXIT_FAILURE Value for the exit function to return in case of program termination due to failure.
RAND_MAX Maximum value returned by the rand function.
__FILE__ Contains the current filename as a string.
__LINE__ Contains the current line number as a integer constant.
__DATE__ Contains current date in "MMM DD YYYY" format.
__TIME__ Contains current time in "HH:MM:SS" format.

C Program to print value of Predefined Macros

#include <stdio.h>
#include <stdlib.h>

int main(){
   printf("NULL : %d\n", NULL );
   printf("EXIT_SUCCESS : %d\n", EXIT_SUCCESS );
   printf("EXIT_FAILURE : %d\n", EXIT_FAILURE );
   printf("RAND_MAX : %d\n", RAND_MAX );
   printf("File Name : %s\n", __FILE__ );
   printf("DATE : %s\n", __DATE__ );
   printf("Line : %d\n", __LINE__ );

   return 0;
}

Output
NULL : 0
EXIT_SUCCESS : 0
EXIT_FAILURE : 1
RAND_MAX : 32767
File Name : PreProcessorMacro.c
DATE : Jan 27 2015
Line : 12

Best Practices for Using Preprocessor Directives

Although preprocessor directives provide flexibility and capability, their improper application can result in difficulties in maintaining code and decreased readability. Below are certain recommended guidelines to adhere to while utilizing preprocessor directives:
  • Limit Use of Macros : Excessive utilization of macros can complicate the readability and troubleshooting of code. Employ them prudently in situations when they truly enhance the comprehensibility of the code.

  • Avoid Complex Macros : Macros that involve several statements or side effects might be prone to errors and difficult to troubleshoot. It is advisable to utilize inline functions instead when dealing with more intricate jobs.

  • Use Header Guards : It is vital to incorporate header guards in your header files to avert the occurrence of duplicate inclusions. This guarantees that your header files are included just once.

  • Be Mindful of Code Portability : Certain preprocessor directives and macros may lack compatibility across different compilers or systems. Take into consideration the potential problems related to mobility while utilizing them.

  • Document Your Code : Thoroughly document the intended function and application of macros and preprocessor directives. Documenting your code enhances comprehensibility and facilitates efficient maintenance for fellow developers.

Conclusion

In conclusion, preprocessor directives in C provide a powerful mechanism for code customization, organization, and optimization. Understanding the basics, common directives, and advanced features such as macros, file inclusion, and predefined macros empowers developers to write more flexible and maintainable code.