C Preprocessors - GeeksforGeeks

C Preprocessors

Last Updated : 12 Nov, 2026

Preprocessors are programs that process C source code before the actual compilation starts. They handle tasks such as macro expansion, header file inclusion, and conditional compilation, and then pass the modified code to the compiler.

  • It is the first stage in the C compilation process.
  • Supports directives such as #define, #undef, #include, #if, #ifdef, #ifndef, #pragma, #error, and #line.

Working of C Preprocessor

The preprocessor works before the compiler and prepares the source code for the remaining stages of compilation.

In the compilation flow, the source file is first given to the preprocessor. It expands macros, inserts header file content, and processes conditional directives. The output of this stage is a preprocessed file, which is then sent to the compiler.

Types of C Preprocessor Directives

C preprocessor directives are commonly classified into the following four categories:

1. Macros

Macros are preprocessor directives used to define constants or function-like substitutions that are expanded before compilation.

  • #define creates a macro.
  • #undef removes a previously defined macro.

Syntax:

#define token replacement_text
#undef token

Here,

  • token is the macro name.
  • replacement_text is the value or expression that replaces the macro during preprocessing.
C
#include <stdio.h>

// Macro Definition
#define LIMIT 5

int main(){
    for (int i = 0; i < LIMIT; i++) {
        printf("%d \n", i);
    }
    return 0;
}

Output
0 
1 
2 
3 
4 

Explanation: Before compilation, the preprocessor replaces every occurrence of LIMIT with 5. Here, LIMIT is the macro name, and 5 is its replacement text.

Note: Macro definitions do not end with a semicolon (;).

C also provides several predefined macros such as __FILE__, __LINE__, __DATE__, and __TIME__, which supply useful information during compilation. A previously defined macro can be removed using the #undef directive.

C
#include <stdio.h>

// Macro Definition
#define LIMIT 5

// Undefine macro
#undef LIMIT

int main(){
    for (int i = 0; i < LIMIT; i++) {
        printf("%d \n", i);
    }
    return 0;
}

Output

./Solution.c: In function 'main':
./Solution.c:10:25: error: 'LIMIT' undeclared (first use in this function)

Explanation: After LIMIT is undefined, the preprocessor no longer replaces it with 5, so the compiler reports an error.

2. Macros With Arguments

Function-like macros accept parameters and expand them during preprocessing, similar to simple functions.

  • Accept arguments to create reusable code snippets.
  • Expanded by the preprocessor without any function call overhead.

Syntax:

#define MACRO_NAME(arg1, arg2) replacement_text

C
#include <stdio.h>

// macro with parameter
#define AREA(l, b) (l * b)

int main(){
    int a = 10, b = 5;
    
    // Finding area using above macro
    printf("%d", AREA(a, b));
    return 0;
}

Output
50

Explanation: The macro AREA(l, b) expands to ((l) * (b)). When AREA(a, b) is used, the preprocessor replaces it with ((a) * (b)), and the expression is evaluated during compilation.

3. File Inclusion

The #include directive is used to include declarations and definitions from external files, such as header files.

  • Includes system or user-defined header files.
  • Promotes code reuse and modular programming.

Syntax:

There are two ways to include header files.

#include <file_name>
#include "filename"

  • <file_name> tells the preprocessor to search for the file in the standard system directories.
  • "file_name" tells the preprocessor to first search the current source file's directory and then the standard directories if needed.

The < > notation tell the compiler to look for the file in the standard directory while double quotes ( " " ) tell the compiler to search for the header file in the source file's directory.

C
// Includes the standard I/O library
#include <stdio.h>  

int main() {
    printf("Hello World");
    
    return 0;
}

Output
Hello World

4. Conditional Compilation

Conditional compilation allows parts of a program to be compiled only when specified conditions are met.

  • Uses directives such as #if, #ifdef, #ifndef, #elif, #else, and #endif.
  • Commonly used for platform-specific code, debugging, and optional features.

Syntax

#if
// some code
#elif
// some more code
#else
// Some more code
#endif

#endif directive is used to close off the #if, #ifdef, and #ifndef opening directives.

C
#include <stdio.h>

// Defining a macro for PI
#define PI 3.14159

int main(){
  
// Check if PI is defined using #ifdef
#ifdef PI
    printf("PI is defined\n");

// If PI is not defined, check if SQUARE is defined
#elif defined(SQUARE)
    printf("Square is defined\n");

// If neither PI nor SQUARE is defined, trigger an error
#else
    #error "Neither PI nor SQUARE is defined"
#endif

// Check if SQUARE is not defined using #ifndef
#ifndef SQUARE
    printf("Square is not defined");

// If SQUARE is defined, print that it is defined
#else
    printf("Square is defined");
#endif

    return 0;
}

Output
PI is defined
Square is not defined

Explanation: Since PI is defined, the first conditional block is executed. The second block checks whether SQUARE is undefined, so it prints "Square is not defined".

5. Other Directives

Besides macros, file inclusion, and conditional compilation, C provides a few additional preprocessor directives for compiler-specific behavior and error handling.

#pragma

The #pragma directive provides compiler-specific instructions to control compiler behavior, such as warnings, memory alignment, and optimization.

  • Used to configure compiler-specific settings.
  • Support varies across different compilers.

Note: #pragma directives are compiler-specific and are not part of the C standard.

#error

The #error directive generates a compilation error with a custom message. It is commonly used with conditional compilation to stop compilation when required conditions are not met.

Syntax

#error "Error message"

#line

The #line directive changes the line number and optionally the filename reported by the compiler. It is mainly used by code generators and debugging tools.

Syntax

#line line_number "filename"

Important Points About C Preprocessors

  • Preprocessor directives begin with the # symbol.
  • They are processed before the compilation stage starts.
  • They do not end with a semicolon.
  • They can modify source code before the compiler sees it.
  • They are widely used for constants, reusable code, header inclusion, and conditional code selection.
Comment