Preprocessing

In this tutorial, we will understand what is preprocessing and how preprocessor performs preprocessing.


Preprocessing is the process of converting source code (with a .c extension) to expanded source code (with a .i extension). This process is performed by the preprocessor.

In a nutshell, the preprocessor is like an editing program (like Microsoft Word, which is precisely a document editor) that takes source code as input and generates expanded source code as output.

Precisely, the job of preprocessor is to do the following:

  1. Remove comments
  2. Expand header files
  3. Expand macros

So, the expanded source code is the updated source code which does not include comments, names of the header files, and macros.


What are comments, and why does the preprocessor remove them?

Comments are additional pieces of information added by programmers to keep notes in different parts of the code.

For example, the following program has two comments (starting with //):

int main() {
     // starting point of the program
     int main() {
         // prints Hello World!
         printf(“Hello World!”);
         return 0;
     }
 }

The preprocessor removes comments because they do not contribute anything to the implementation or execution of the program, apart from helping programmers or other readers understand different parts of the program. Since comments are not intended for computer instructions, the preprocessor removes them.


What does it mean that the preprocessor expands the header files?

In the previous tutorial, I mentioned that we need to include the stdio.h header file in our program to use the printf() function, which is available in this header file. In reality, it is the preprocessor’s job to include the contents of the header file. This is what is meant by “the preprocessor expands the header file.”

The #include statement is a preprocessor directive, which means that the statement following it is intended to be processed by the preprocessor. So, when we encounter a statement starting with #include, we know that it is meant to be processed by the preprocessor.

But what is there inside stdio.h?

The stdio.h library contains declarations for many standard input and output functions, as well as all the necessary information for including them in your code. You may have heard the terms declaration and definition before, which are common in the world of programming languages.

A function declaration tells the compiler that the function we want to use is available somewhere for us to use. It is like giving a guarantee to the compiler that the function already exists. On the other hand, a function definition refers to the actual code of the function, the logic that makes up the function. Built-in functions are already defined by someone, so we just need to declare them and use them. Consequently, stdio.h contains function declarations because that’s all we need.

What’s the problem in including the definitions in the header files?

Firstly, there is no need to compile the built-in functions, as they are pre-compiled and ready to use. Secondly, commonly used header files like stdio.h contain hundreds of lines of code for each function, making re-compiling these functions unfeasible. Therefore, it is better to add just declarations of the functions in the header file. By doing this, we tell the compiler that we may use some or all of these functions later in our code, and to skip the definitions for now. The definitions of the specific functions used in the program will be provided later. This allows us to pass the compilation phase without any errors.


What is the meaning of “preprocessor expands macros”?

First, let’s understand the meaning of macro.

A macro is a piece of code that the preprocessor replaces with the macro’s value. It is defined using the #define directive.

#include <stdio.h> 
#define N 10
int main()
{
   printf("The value of N is %d", N);
   return 0;
}

Output:

The value of N is 10
Process returned 0 (0x0)   execution time : 1.883 s
Press any key to continue.

In the above program, N indicates the name of the macro, and 10 represents its value. The printf() method has two inputs. The first is a string with the placeholder %d, which the preprocessor replaces with the value of N (the second input). This is one of the reasons why the preprocessor is often referred to as the “editor.” The output of the preceding program is “The value of N is 10.”

Therefore, “preprocessor expands macros” means that it replaces the macro names with their values.

Now that we know exactly what a preprocessor is and what it does, we can understand that the result of preprocessing is the expanded source code with the .i extension. However, Code::Blocks does not provide us with this file automatically. We need to manually obtain it using the command prompt. Let’s learn the process of obtaining the expanded source code.


Getting the expanded source code

GCC (GNU Compiler Collection – a package containing everything needed to generate the final output) provides us with the ability to see the preprocessed expanded source, which is originally hidden from us. But before we get into the process, please write the following code in Code::Blocks (or the IDE of your choice) and save it in the C Programs folder as add.c.

#include <stdio.h>
#define N 10

// starting point of the program
int main()
{
    printf("The value of N is %d", N);
    return 0;
}

We will not build and run this code in the IDE. Instead, we will open the command prompt, navigate to the folder where the file add.c is stored (presumably the C Programs folder), and enter the following command:

gcc -E add.c -o add.i

In the above command

  1. gcc allows us to call the GNU Compiler Collection.
  2. -E is the flag that stops every other process except preprocessing.
  3. -o creates a new file and stores the result of preprocessing (expanded source code) in this file.
  4. add.i is the name of the file where the expanded source code will be stored.

After executing the above command, a new file named add.i will be created in our C programs folder. If you open this file in the IDE, you will see a lot of code added by the preprocessor. If you scroll down to the bottom, you will see the code we wrote, as follows:

int main()
{
    printf("The value of N is %d", 10);
    return 0;
}

It can be observed that all operations are performed by the preprocessor, including:

  1. Removing the comment “//starting point of the program“.
  2. Expanding the header file.
  3. Replacing the macro N with its value 10.

This verifies the preprocessing stage.



Leave a comment

Leave a comment

Your email address will not be published. Required fields are marked *

Thank you for choosing to leave a comment. Please be aware that all comments are moderated in accordance with our policy. For more information, please review our comments policy. Rest assured that your email address will not be shared with anyone. Kindly refrain from using keywords in your comment. Let’s maintain a respectful atmosphere and engage in meaningful conversations.