Preprocessors in C

In C, preprocessors are one of the most important and useful concepts. Preprocessor allows you to define macros that transform your program before it is compiled. C preprocessor is also known as CPP.

working of preprocessors in c

What are preprocessor in C?

C preprocessors tell the compiler to do the required processing before its compilation. From the word ‘preprocessor’, you already know the meaning of it. ‘Pre’ means before and ‘processor’ means making something. It is not part of the compiler but it is considered as a separate step in the compilation process.

Suppose, we have a c file named main.c with extension of .c. Preprocessors then process this file and in the next step, it gets compiled and it produces an object file with extension of .obj. After that the .obj file is linked with standard library functions to generate a file with extension of .exe and then it executes.

What are C Preprocessor directives?

It tells the compiler to preprocess the source code before compiling. Preprocessor Directives mainly used as commands. In C, all the preprocessor directives start with a hash/pound(#) symbol. You can use preprocessor directives anywhere in the program. But it is best to use the preprocessor directives at the beginning of the program.

Example:-

#define PI 3.14

Types of Preprocessor in C

There are 4 main types of preprocessor directives:-

  • Macros
  • File Inclusion
  • Conditional Compilation
  • Other directives

1. Macros in C

Programmers use macros to execute pieces of code inside the macro. A programmer gives a name to the macro. And when the given name is encountered by the compiler then the compiler replaces the name with the piece of code which is inside the macro. The #define directive is used to define a macro.

Example of C Macros

#include <stdio.h>
#define LIMIT 4 // defining macro!
int main()
{
for (int a = 0; a < LIMIT; a++) {
printf("%d \n",a);
}
return 0;
}

Output

0
1
2
3

In the above example, the compiler replaces LIMIT with 5. LIMIT is a macro template and 5  is macro expansion.

Macros with arguments

We can also pass arguments to the macros. Macros with arguments work similarly as functions.

Example of Macros with arguments:-

#include <stdio.h>
#define AREA(s) (s * s) // macro with argument
int main()
{
int s1 = 10, area_of_square;
area_of_square = AREA(s1);
printf("TechVidvan Tutorial: Macros with arguments!\n");
printf("Area of square is: %d", area_of_square);
return 0;
}

Output

TechVidvan Tutorial: Macros with arguments!
Area of square is: 100

In the above example, the compiler finds the name of the macro (AREA(s)) and replaces it with the statement (s * s).

Function like Macros in C

Define macros that work similarly like functions.

Example of Function like Macros in C

#include <stdio.h>

#define MIN(a,c) ((a) > (c) ? (c) : (a))

int main(void) {
   printf("Between 30 and 70, minimum number is: %d\n", MIN(10, 20));  
   return 0;
}

Output

Between 30 and 70, minimum number is: 10

2. File Inclusion

This preprocessor directive tells the compiler to include a file in the program code. A user can include two types of file:-

a. Header or Standard files

These files contain functions like printf(), scanf(). In a single word, it contains predefined functions. Different header files contain different functions. Like, string file contains string handling functions and iostream file contains input/output functions.

Syntax:-

#include <name_of_the_file>

b. user defined files

A programmer can define his/her own header file to divide a complex code into small blocks of code.

Syntax:-

#include"filename"

3. Conditional Compilation in C

The main purpose of this preprocessor directive is to compile specific parts of the code or skip the compilation of specific parts of the code based upon some conditions.

How to use conditional compilation directives?

With the help of two preprocessing methods, you can implement the conditional compilation directive.

  • ifdef
  • endif

Syntax:-

#ifdef macro_name
    statement1;
    statement2;
    statement3;
    .
    .
    .
    statementN;
#endif

If the macro name is defined, then it will normally execute the block of statements. And if it is not defined, then the compiler will skip the block of statements.

Apart from #ifdef and #endif directives, there are some other directives such as #if, #elif, #else and #defined directives.

#if, #elif, #else directive in C

You can also use #else directive with #if directive. If the given expression results in a non zero value, then the codes of conditional are included in the program.

Syntax:-

#if expression
// conditional statements if expression is not zero
#else
// conditional statements if expression is zero
#endif

You can also use nested conditional in your program with the help of #elif directive.

Syntax:-

#if expression1
// conditional statements if expression1 is not zero
#elif expression2
// conditional statements if expression1 is not zero
#else
// conditional statements if all expressions is zero
#endif

#defined directive in C

Mainly used to check whether a certain macro is defined or not. You can use #if directive with #defined directive.

Syntax:-

#if defined LENGTH || WIDTH >= 10
  // body contains code

Uses of C Conditional Compilation:-

  • Compile the same source file in different programs.
  • Depending on the OS, you can use different code.

4. Other directives in C

There are also two not so used directives available in C.

a. #undef directive:- Mainly used to undefine an existing macro.

Syntax:-

#undef LIMIT

If you use the above statement then it will undefine the existing macro LIMIT.

b. #pragma directive:- Mainly used to enable or disable certain features. It varies from compiler to compiler. Below is some of the pragma directives:-

  • #pragma startup and #pragma exit:– Mainly used to specify the functions which are needed to run before program startup and before program exit.

Example:- pragma startup and pragma exit

#include <stdio.h>
void f1();
void f2();
#pragma startup f1
#pragma exit f2
void f1()
{
  printf("Executing f1() function!\n");
}
 
void f2()
{
  printf("Executing f2() function!\n");
}
 
int main()
{
  void f1();
  void f2();
  printf("TechVidvan Tutorial: pragma startup and pragma exit!\n\n");
  printf("Executing main() function!\n");
 
  return 0;
}

Output

TechVidvan Tutorial: pragma startup and pragma exit!

Executing f1() function!
Executing main function!
Executing f2() function!

But if you run this in GCC compiler, it will give output like this:-

TechVidvan Tutorial: pragma startup and pragma exit!

Executing main function!

Because GCC compiler does not support #pragma startup or #pragma exit.

  • #pragma warn directive:- Mainly used to hide warning messages that are displayed while compilation.
  • #pragma warn -rvl:- Mainly used to hide the warnings when a function does not return a value as it is supposed to.
  • #pragma warn -par:- Mainly used to hide the warnings when a function does not use the parameters which are passed to it.
  • #pragma warn -rch:- Mainly used to hide the warnings when a code is unreachable.

C Preprocessor Examples:-

Below are some examples of preprocessors:-

#define SIZE 42

In the above example, the compiler will automatically replace the macro name SIZE with 42.

#include <string.h>
#include "header.h"

In the above example, we added the string.h header file to make use of string handling functions. And also, we added our own header.h file from the local directory.

#undef TEST

It tells the compiler to undefine existing TEST.

#ifndef MOTD
   #define MOTD "TechVidvan Tutorial: P"
#endif
In the above example

In the above example, we have defined MOTD only if MOTD is not defined already. MOTD means message of the day.

How does a preprocessor work in C?

Below are the steps involved while preprocessing:-

1. Filtering out comments:– In C, comments are used for better understanding of different steps which are included in the program. Compiler filters out the comments during processing.

2. File Inclusion:– It tells the compiler to include certain header files so that certain functions can be performed. In 2 ways, you can do it:-

  • #include<filename.h>
  • #include”filename.h”

3. Macro Expansion:– In some situations, you will need to use some blocks of code in a recursive function. In 2 ways, you can do it:-

4. Object-like macros:– Does not take parameters.

5. Function-like macros:– Capable of taking parameters.

Example of Object-like Macros

#include <stdio.h>
#define SIDE 4
int main() {
  int area;
  area = SIDE*SIDE;
  printf("TechVidvan Tutorial: Object Like Macros!\n");
  printf("Area is: %d",area);
  return 0;
}

Output

TechVidvan Tutorial: Object Like Macros!
Area is: 16

In the above example, SIDE is the macro name and it will be replaced by value 4.

Below is a table of preprocessor in C:-

Preprocessor What it does
#include To insert a specific header from a file.
#define Mainly used as a replacement of a preprocessor macro.
#ifdef If the macro is defined, it returns true. And if not, then false.
#endif Mainly used to close the preprocessor directive.
#undef To undefine a standard or user-defined header.
#pragma To enable and disable certain features.
#ifndef Returns true when micro is not defined.
#if Checks if the condition is true at compile time.
#else Checks the next condition if #if proves to be false in compile time.
#elif Used as a combination of #else and #if.
#error Mainly used to print errors on stderr.

Predefined Macros in C

One should not modify the predefined macros. Below are some predefined macros.

MACRO  What it does
__DATE__ Current date as MMM DD YYYY format.
__TIME__ Current time as HH:MM:SS format.
__FILE__ Contains current filename.
__LINE__  Contains current line number.
__STDC__ Defined as 1 when the compiler compiles.

Example of C Predefined Macros

#include <stdio.h>
int main() {
printf("TechVidvan Tutorial: Predefined Macros!\n\n");
char filename[] = __FILE__;
char date[] = __DATE__;
char time[] = __TIME__;
int line = __LINE__;
int ansi = __STDC__;
printf("File name is: %s\n", filename);
printf("Date is: %s\n", date);
printf("Now time is: %s\n", time);
printf("Current line number: %d\n", line);
printf("Compilation Success: %d\n", ansi);
}

The above code is saved in a file named HelloWorld.c.

Output:-

TechVidvan Tutorial: Predefined Macros!

File name is: main.c
Date is: Jun 11 2021
Now time is: 08:58:39
Current line number: 7
Compilation Success: 1

Preprocessor Operators in C

There are various operators that help to create macros.

1. Macro Continuation(/) operator in C

Mainly used to continue a macro which is too long to a single line.

Example:- Macro Continuation

#define  message_of_the_day(i, j)  \
   printf(#i " and " #j ": TechVidvan Tutorial: Macro Continuation!")

2. Stringize Operator(#) in C

The main purpose of this operator is to convert a macro parameter into a string.

Example of Stringize Operator

#include <stdio.h>
#define statement(i)  \
  printf(#i ": Macro Stringize!\n")
 
int main(void) {
   statement(TechVidvan Tutorial);
   return 0;
}

Output:-

TechVidvan Tutorial: Macro Stringize!

3. Defined() Operator in C

Mainly used to determine if an identifier is defined. If it is defined, then the value will be non-zero.

Example:- Defined() Operator

#include <stdio.h>
#if !defined (MSG)
   #define MSG "Macro Defined() operator!"
#endif

int main(void) {
   printf("TechVidvan Tutorial: %s\n", MSG);  
   return 0;
}

Output:-

TechVidvan Tutorial: Macro Defined() operator!

4. Token Pasting(##) Operator in C

Mainly used to combine two arguments.

Example:- Macro Token Pasting

#include <stdio.h>
#define tokenpaster(num) printf ("token" #num " = %d", token##num)
int main(void) {
int token1 = 21;
printf("TechVidvan Tutorial: Token Pasting(##) operator\n\n");
   tokenpaster(1);
   return 0;
}

Output

TechVidvan Tutorial: Token Pasting(##) operator

token1 = 21

Summary

There are 4 main types of preprocessor directives in C. Preprocessor allows you to define macros that transform your program before it is compiled.

Programmers use macros to execute pieces of code inside the macro. The #define directive is used to define a macro. ‘Pre’ means before and ‘processor’ means making something.