This blog gives you a comprehensive guide to preprocessor directives in C. We will discuss all four major types of preprocessor directives with their use cases and examples to make you understand the purposes of different directives.
Table of Contents
Watch the video below to learn the fundamentals of C:
What are Preprocessor Directives in C?
Preprocessor directives in C are the commands used by the preprocessor, which is a part of the compiler. The work of these preprocessors is to perform certain actions before beginning the actual compilation process. Preprocessor directives start with a # symbol and provide instructions to the preprocessor on how to preprocess the source code. They manipulate the source code by performing text replacement, file inclusion, conditional compilation, and other tasks. This way, preprocessor directives help developers write more flexible and maintainable code.
Learn the fundamentals and advanced concepts of C with C Programming Certification Course!
List of Preprocessor Directives in C
Here is a list of some commonly used preprocessor directives in C, along with the functionality they provide in code:
Preprocessor Directive | Description |
#include | Includes the contents of another file in the current file |
#define | Defines a macro with a replacement text |
#undef | Undefines a previously defined macro |
#ifdef | Checks if a macro is defined |
#ifndef | Checks if a macro is not defined |
#if | Compiles following code if a condition is true |
#elif | Compiles following code if a different condition is true |
#else | Compiles following code if the #if condition is not true |
#endif | End of a conditional compilation block |
#error | Generates an error message |
#pragma | Provides compiler-specific instructions |
#line | Changes the line number for the compiler |
FILE | Built-in macro that expands to the current file name |
LINE | Built-in macro that expands to the current line number |
DATE | Built-in macro that expands to the compilation date |
TIME | Built-in macro that expands to the compilation time |
Workflow of Preprocessor Directives in C
The preprocessor directives are processed before the actual compilation of the C program. The following diagram illustrates the workflow of preprocessor directives in C:
The steps that are followed before the actual compilation of code, including the role of preprocessor directives, are given below:
- The program begins with the source file containing C code and preprocessor directives.
- The preprocessor reads the source file and processes each line.
- During macro expansion, the preprocessor replaces all occurrences of macros with their corresponding text strings.
- The preprocessor evaluates conditional directives like #ifdef, #ifndef, #if, #elif, and #endif. Based on the results of the evaluation, the preprocessor selectively includes or excludes sections of the code.
- Then #include directive allows the preprocessor to include the contents of another file in the current file, if there are any.
- After processing all directives, the preprocessor generates a modified source file containing only the actual C code that is to be further compiled.
- The modified source file is then passed to the C compiler, which compiles it into machine code.
- The machine code is the final executable code that can be run by the computer.
Explore our C tutorial for a comprehensive guide to the C Programming Language!
Types of Preprocessor Directives in C
We can divide preprocessor directives in C into four categories which are as follows:
1. File Inclusion Directives (‘#include’)
This directive is used to include header or source files in the current source file before compilation. With the help of these directives, one can declare or define source code from other files in your program. One commonly used file inclusion directive is ‘#include <stdio.h>’. It is used to include the standard I/O library, or we can use ‘#include “my_header.h”‘ to include a user-defined header file.
Syntax for defining the file inclusion directive:
#include <file name>
Let’s understand the implementation of the file inclusion directive with the help of one example:
#include <stdio.h> // Here we have declared file inclusion directive
main()
{
printf(“Hello World”);
}
2. Macro Definition Directives (‘#define’)
These directives are used to create symbolic constants or macros. When the preprocessor encounters these macros in the code, it replaces them with the specified values or expressions before the actual compilation begins. For example, ‘#define PI 3.14159’ defines a macro named ‘PI’ with the value ‘3.14159’. This means that wherever the ‘PI’ in the code appears, it will be replaced by its value (3.14159) during preprocessing.
Syntax for defining macro directives:
#define identifier string
Here is an example that displays how we can define macros in code:
#include <stdio.h>
#define TEMP 100
main()
{
printf("THE VALUE OF PI IS: %f",TEMP);
}
In the above example, we have defined a macro ‘TEMP’ whose value is 100. This means that wherever we use TEMP in our code, 100 will be assigned automatically to that variable.
3. Conditional Compilation Directives (‘#ifdef’, ‘#ifndef’, ‘#if’, ‘#else’, ‘#elif’, ‘#endif’)
These directives allow parts of the code to be included or excluded from the final compiled output based on certain conditions or pre-defined macros. Here are some of the most commonly used conditional compilation directives.
- ‘#ifdef’ checks if a macro is defined.
- ‘#ifndef’ checks if a macro is not defined.
- ‘#if’, ‘#else’, ‘#elif’, and ‘#endif’ are used for conditional compilation based on expressions.
Syntax for defining Conditional Compilation Directives:
#ifdef nameofdirective
Let’s understand the use case of conditional compilation directives with the following example:
#define DEBUG 1
#ifdef DEBUG
// Code included only if DEBUG is defined
printf("Debugging information\n");
#endif
Check out C and Data Structure Interview Questions to crack your next interview!
4. Line Control (‘#pragma’, ‘#error’, ‘#warning’, etc.)
Here are some commonly used directives that are used for identifying errors in particular lines of code for different purposes, described as follows:
- ‘#pragma’ provides instructions not standardly defined by the compiler. For example, it can control optimizations or align memory.
- ‘#error’ generates a compilation error with a specified error message. It is specially used for enforcing specific conditions or restrictions.
- ‘#warning’ generates a compilation warning with a specified warning message. It is used by developers to get notifications about certain conditions or requirements.
Syntax for declaring the line control directives is as follows:
Syntax 1
# line-number “file_name”
Syntax 2
# line line-number “file_name”
Here is an example demonstrating the use of line control directives in a program:
#include <stdio.h>
void func_1();
void func_2();
#pragma startup - func_1
#pragma exit - func_2
void func_1()
{
printf("Inside the func_1()\n");
}
void func_2()
{
printf("Inside the func_2()\n");
}
int main()
{
void func_1();
void func_2();
printf("Inside the main()\n");
return 0;
}
Learn how to use Dynamic Memory Allocation in C to improve your code!
Conclusion
Preprocessor directives play a major role in shaping the final C code by performing tasks like macro expansions and conditional compilation. Understanding their types and workflow helps us write more concise, modular, and efficient C code. Preprocessor directives give the flexibility to add personalized source code inside a program.
FAQs
What are the best practices when using preprocessor directives?
The best practice while using preprocessor directives is to use preprocessor directives wisely and as precisely as possible to enhance code readability and maintainability.
Can preprocessor directives affect code performance?
Yes, extensive or improper use of preprocessor directives might have an impact on code performance.
Are there any alternatives to preprocessor directives in C?
There are some potential alternatives or modern practices that could replace or complement preprocessor directives in certain scenarios.