C/C++ Preprocessors

C/C++ Preprocessors

C/C++ preprocessors are powerful tools that play a crucial role in the software development process. These tools are responsible for processing and modifying the source code before actual compilation, enabling developers to streamline their work, enhance code reusability, and improve code maintenance. By handling tasks such as including header files, defining macros, and performing conditional compilation, C/C++ preprocessors help shape the code and make it more efficient, readable, and adaptable. In this introductory exploration, we will delve into the world of C/C++ preprocessors to understand their significance and how they enhance the development of software in these programming languages.

What are C/C++ Preprocessors

Preprocessors are those which can process source code before compilation. There are several steps that will involve writing a program and executing the program in C/C++.

  1. Preprocessing: The source code file “program.c” is processed by preprocessors. This step results in the creation of an expanded source code file known as “program.i.”
  2. Compilation: The “program.i” file, which has been expanded by the preprocessor, is then compiled by the compiler. The compiler’s job is to translate the code into a lower-level language or machine code. The outcome of this step is an object code file named “program.obj.”
  3. Linking: The linker comes into play. It takes the “program.obj” file and combines it with object code from library functions. This linking process results in the generation of the final executable file named “program.exe.”

Preprocessor Directives in C/C++

The Preprocessor program will provide the preprocessor directive that can guide the compiler to preprocess the source code before compiling. Preprocessor directives will begin with a (# ) symbol. This # symbol will refer to whatever statement begins with # and, further, it will go to the preprocessor program to be executed. Thereafter, we can even place these preprocessor directives anywhere in the program.

The following table about the preprocessor directives in C/C++:

Preprocessor DirectivesDescription
#defineIt is used to define a macro
#undefIt is used to undefine a macro
#includeThis preprocessor is used to include a file in the source code program
#ifdefThis is used to include a section of code if a certain macro is not defined by #define
#ifndefThis is used to include a section of code when a certain macro is not defined by #define
#ifUsed to monitor the specified condition
#else# else is another alternative that will execute when#if fails
#endifIt is used to indicate the end of #if,#ifdef, and#ifndef

Types of C/C++ Preprocessors

4 Main types of preprocessor directives are:

  1. Macros
  2. File Inclusion
  3. Conditional Compilation
  4. Other directives

1. Macros

In C/C++, macros are like shortcuts for code. They are created by giving a name to a piece of code. When the compiler sees this name in your program, it replaces it with the actual code. To make macros, we use the #define directive. This allows us to define these handy code snippets for reuse in our programs.

Syntax of Macro Definition

#define token value

Example

// C Program to illustrate the macro
#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

The above program illustrates that the compiler will execute the word LIMIT and later, it will replace it with 5. Hence, LIMIT in the macro definition is known as the macro template, and 5 as the macro expansion.

Macros With Arguments

Macros in C/C++ can indeed be defined with arguments, and they work somewhat like functions. When you define a macro with arguments, you can use those arguments within the macro code to make it more flexible and versatile. These macros are known as “function-like macros.” They enable you to create reusable code blocks with parameters, similar to functions, but they are preprocessed and substituted directly into your code, often resulting in more efficient code execution.

Example

#define foo(a, b) a + b
#define func(r) r * r

// C Program to illustrate function like macros
#include <stdio.h>
 
// macro with parameter
#define AREA(l, b) (l * b)
 
int main()
{
    int l1 = 10, l2 = 5, area;
 
    area = AREA(l1, l2);
 
    printf("Area of rectangle is: %d", area);
 
    return 0;
}

Output

Area of rectangle is: 50

The program you’ve described illustrates how macros work. When the compiler encounters the macro AREA(l, b) in your code, it directly replaces it with the statement (l * b). Additionally, any values you pass to the macro, like in AREA(10, 5), will also be substituted into the statement. So, AREA(10, 5) is effectively equal to 10 * 5, making it a simple way to create reusable code snippets with dynamic values.

2. File Inclusion

This type of preprocessor directive will insist the compiler to include a file in the source code program. The #include preprocessor director will include the header files in the C/C ++ program.

There are two types of files that can be included by the user in the program:

Standard Header Files

The stanard header file will contain definition of pre-defined function such as print f () , scan(). Those files should be included to work with those functions. Additionaly, different functions will declared in different header files.

So, standard I/O function will be in the ‘iostream file’, and functions that will perform string operation will be in the string file.

Syntax

#include <file_name>

In the syntax given above, file_name refer to the name of the header file that should be included. The < and > brackets will assist the compiler to search the file in the standard directory.

User-defined Header Files

When a program turns into large, it is better to change into smaller files and the, include them in whatever required. Those types of files are user-defined header files. They can be included as:

#include "filename"

(“” ) These double quotes will tell about the compiler and to look for the header file in the source file’s directory.

3. Conditional Compilation

It is a type of directive which is used to compile a small portion of the program or skip the compilation of some specific part of the program depending on certain conditions. Preprocessor directive which are used to insert the conditional code.

  1. #if Directive
  2. #ifdef Directive
  3. #ifndef Directive
  4. #else Directive
  5. #elif Directive
  6. #endif Directive

#endif directive functions to close off the #if, #ifdef, and #ifndef opening directives, and it refers that the preprocessing of these directives is hence completed.

Syntax

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

Other Directive

The directive that are not commonly used are:

  1. #undef Directive
  2. #pragma Directive

1. #undef Directive

This is used to undefine an existing macro.

#undef LIMIT

 After this statement, every “#ifdef LIMIT” statement will be evaluated as false. 

2. #pragma Directive

This directive has a special purpose directive and, also to turn on or off some features. These types of directives are basically compiler-specific, i.e., they will vary from compiler to compiler. Some of the #pragma directives are discussed below: 

  1. #pragma startup: These directives are used to specify the functions that are required to run before program startup (before the control passes to main()).
  2. #pragma exit: These directives help us to specify the functions that are needed to run just before the program exit (just before the control returns from main()).

Example

// C program to illustrate the #pragma exit and pragma
// startup
#include <stdio.h>
 
void func1();
void func2();
 
// specifying funct1 to execute at start
#pragma startup func1
// specifying funct2 to execute before end
#pragma exit func2
 
void func1() { printf("Inside func1()\n"); }
 
void func2() { printf("Inside func2()\n"); }
 
// driver code
int main()
{
    void func1();
    void func2();
    printf("Inside main()\n");
 
    return 0;
}

Output

Inside main()

Expected Output

Inside func1()
Inside main()
Inside func2()

While running on GCC Compilers, it will show output as below:

Inside main()

This happens as GCC won’t support #pragma startup or exit. Hence, you can use the below code for the expected output on GCC compilers. 



#include <iostream>
using namespace std;
 
void func1();
void func2();
 
void __attribute__((constructor)) func1();
void __attribute__((destructor)) func2();
 
void func1()
{
    printf("Inside func1()\n");
}
 
void func2()
{
    printf("Inside func2()\n");
}
 
// Driver code
int main()
{
    printf("Inside main()\n");
 
    return 0;
}

Output

Inside func1()
Inside main()
Inside func2()

#pragma warn Directive

This directive intends to hide the warning message that are displayed during compilation. We can hide the warnings as shown below: 

  • #pragma warn -rvl: This directive hides those warnings that are raised when a function that is supposed to return a value does not return a value.
  • #pragma warn -par: This directive hides those warnings that are raised when a function won’t use the parameters passed to it.
  • #pragma warn -rch: This directive hides those warnings which are raised when a code is unreachable. For example, any code written after the return statement in a function is unreachable.

FAQ- C/C++ Preprocessors

Q1. What is the preprocessor in C++?

Ans. The preprocessor can perform the preliminary operations on C and C++ files before they are passed to the compiler. Therefore, you can add the preprocessor to conditionally compile code, insert files, specify compile-time error messages, and apply machine-specific rules to sections of code

Q2. What is #define in C++?

Ans. When you use #define in your code, you create a macro that associates an identifier (or parameterized identifier) with a token string. Once defined, the compiler replaces every instance of that identifier in the source file with the specified token string. This allows you to create shortcuts, constants, or reusable code blocks that make your code more readable and efficient.

Q3. Which of the following are C preprocessors?

Ans. #define, #ifdef, and #endif are all part of the C preprocessor. The C compiler automatically employs the C preprocessor, which is essentially a macro processor, to modify your program before the actual compilation. These preprocessor directives are used to define macros, conditionally include or exclude parts of the code, and perform various other preprocessing tasks to prepare the code for compilation. They are an integral part of the C programming language and contribute to code organization, optimization, and customization.

Hridhya Manoj

Hello, I’m Hridhya Manoj. I’m passionate about technology and its ever-evolving landscape. With a deep love for writing and a curious mind, I enjoy translating complex concepts into understandable, engaging content. Let’s explore the world of tech together

Leave a Comment