A C preprocessor is a statement substitution (text substitution) in C programming language. It instructs the C compiler to do some specific (required) pre-processing before the compilation process.
When we compile a C program, C preprocessor processes the statements which are associated with it and expand them to make the code for further compilation.
The C preprocessor versus the compiler
Please remember that, C preprocessor is not a part of C compiler. It has different syntax from normal C statements compiled by the compiler, for example:
- It start with hash/pound
#
character. - C preprocessor is line oriented. Each statement start in a separate line. While it is not mandatory for other C statements to start in separate line.
- These statements end with new line. While, other statements are terminated by semicolon.
C preprocessor is a Micro preprocessor which compiles the code before the compilation.
List of all preprocessor directives:
- #include preprocessor directive
- #define and #undef preprocessor directive
- Parameterized Macros (Function like Macros)
- #ifdef, #ifndef and #endif preprocessor directive
- #if…#elif…#else…#endif
- Stringize operator (#)
- Token pasting (##)
- #pragma preprocessor directive
- #error preprocessor directive
- #null preprocessor directive
In this post, I won’t explain stringize, token pasting operator, #pragma, #error and #null directives. I will explain them separately to make this post much easier to consume.
#include preprocessor directive (File inclusion directive)
We use #include
directive to include contents of another file (especially header file’s) to a program. We can include a file in two different ways.
-
#include <file.h>
This variant of including header file, searches header file in the “standard header file directory”. Standard header file directory is the path where all header files are stored.Syntax to use
#include <header.h>
Where
header.h
is a standard C header file. -
#include "file"
We use this variant of including file when we want to include our own/custom header file. It searches the file in the current directory and then in the standard header file’s directory.Syntax to use
#include "path_to_header_file";
Where
path_to_header_file
is relative path to the header file.
Example:
#include <stdio.h>
#include "main.h"
#include "win/display.c"
Here, file “stdio.h” is a standard header file, “main.h” and “win/display.c” is custom C files.
#define preprocessor directive
#define
preprocessor directive is the most useful preprocessor directive in C language. We use it to define a name for particular value/constant/expression.
C preprocessor processes the defined name and replace each occurrence of a particular string/defined name (macro name) with a given value (micro body).
Syntax to define a MACRO using #define
#define MACRO_NAME macro_body
Here, MACRO_NAME
is a C identifier and macro_body
is string/value/expression.
Learn more: How to define compile time constants using #define?
Example:
#include <stdio.h>
// Macro definition
#define COUNTRY "INDIA" // String constant
#define TRUE 1 // Integer constant
#define FALSE 0 // Integer constant
#define SUM (10 + 20) // Macro definition
int main()
{
printf("COUNTRY: %s\n", COUNTRY);
printf("TRUE: %d\n", TRUE);
printf("FALSE: %d\n", FALSE);
printf("SUM(10 + 20): %d\n", SUM);
return 0;
}
Output:
COUNTRY: INDIA
TRUE: 1
FALSE: 0
SUM(10 + 20): 30
Here, COUNTRY
, TRUE
and FALSE
are compile time constants and SUM
is a macro. The C pre-processor replaces all occurrences of COUNTRY
with “India” and all other constants with their respective value before compilation.
#undef preprocessor directive
We use #undef
directive to remove a defined macro. We generally un-define a macro, when we do not require or want to redefine it. To redefine a macro, we need to undefined the macro and redefine it.
Syntax:
#undef MACRO_NAME
Where MACRO_NAME
is the macro to remove.
Example:
#include <stdio.h>
// Macro definition
#define TRUE 1
#define FALSE 0
int main()
{
printf("TRUE: %d\n", TRUE);
printf("FALSE: %d\n", FALSE);
// Undefine a previously defined macro
#undef TRUE
#undef FALSE
// Re-define macro values
#define TRUE 0
#define FALSE 1
printf("\nMacro values are redefinition\n");
printf("TRUE: %d\n", TRUE);
printf("FALSE: %d\n", FALSE);
return 0;
}
Output:
TRUE: 1
FALSE: 0
Macro values are redefinition
TRUE: 0
FALSE: 1
Parameterized Macros (Function like Macros)
We use Function like macros to rewrite small functions using macros to save the execution time.
If we use functions, then at every function call programs execution will move between function definition and calling, which consumes time.
To save this time, we can use parameterized macros. The macro definition will be expanded to the function call during pre-processing.
Syntax:
#define MACRO_NAME(parameters) macro_body
Example:
#include <stdio.h>
// Function to fund sum of two numbers
int sum (int a, int b)
{
return (a + b);
}
// Function like Macro for above function
#define SUM(a, b) (a + b)
int main()
{
printf("SUM using function: %d\n", sum(100, 200));
printf("SUM using macro: %d\n", SUM(100, 200));
return 0;
}
Output:
SUM using function: 300
SUM using macro: 300
#ifdef, #ifndef and #endif conditional preprocessor directive
We use conditional directives to check if a macro is defined or not. Both #ifdef
and #ifndef
are complements of each other.
#ifdef conditional directive
#ifdef
will compile all code if a given macro is defined.
Syntax:
#ifdef MACRO_NAME
Where MACRO_NAME
is our macro to test if defined.
#ifndef conditional directive
#ifndef
is similar to #ifdef
just works as a complement. It process block of code if a given macro is not defined.
Syntax:
#ifndef MACRO_NAME
Where MACRO_NAME
is our macro to test if not defined.
Example:
#include <stdio.h>
// MACRO definition
#define COUNTRY "INDIA"
int main()
{
// If COUNTRY is defined, print a message
#ifdef COUNTRY
printf("Country is defined\n");
#endif
// If STATE is not defined, define it
#ifndef STATE
printf("State is not defined. Defining state. \n");
#define STATE "PATNA"
#endif
printf("State is: %s\n", STATE);
return 0;
}
Output:
Country is defined
State is not defined. Defining state.
State is: PATNA
NOTE: Conditional directive #ifdef
or #ifndef
must end with #endif
. #endif
defines scope of the conditional directive.
We use conditional directives to restrict file loading multiple times.
Example: If there is a file named myfile.h which has the declaration of some of the variables and functions. If we include myfile.h in 3 source code (.c) files. The code of the header file will be included 3 times in all files and it may case the multiple declaration error.
To restrict such cases, we can use these directives like given below
Consider the code:
file: myfile.h
#ifndef _MY_FILE_
#define _MY_FILE_
// Declare other macros
// Declare variables and functions
#endif
When file will include first time in any source code file, the C pre-processor will check for macro _MY_FILE_
definition. At the first time, macro is not defined, so the pre-processor defines a macro _MY_FILE_
and declare other variables and functions.
Now, when we include the file for second time the C pre-processor again checks macro definition #ifndef _MY_FILE_
. But this time since its already defined in some other file hence, it gets false
and the declarations will not include again.
#if, #elif, #else and #endif preprocessor directives
C supports conditional compilation pre-processors directives, similar to if…else statements in C. We use them for conditional compilations. C conditional preprocessor directives compiles multiple conditional code blocks.
Syntax:
#if expression
// If condition is true
#elif expression
// If else if condition is true
#else
// If no condition is true
#endif
Example:
#include <stdio.h>
#define IND 1
#define USA 2
#define UK 3
#define COUNTRY IND
int main()
{
#if COUNTRY == IND
printf("Selected country code is: %d\n", COUNTRY);
// Do some task if country is India
#elif COUNTRY == USA
printf("Selected country code is: %d\n", COUNTRY);
// Do some task if country is USA
#else
printf("Selected country code is: %d\n", COUNTRY);
// Do some task if country is UK
#endif
return 0;
}
Output:
Selected country code is: 1
In next upcoming tutorials we will learn about other advanced preprocessor directives supported by C language.
Happy coding 😉