C preprocessor directives – #include, #define, #undef and conditional directives

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:

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.

  1. #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.

  2. #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.

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 😉