Preprocessor



preprocessor

Working of C Preprocessor

ย 
In C programming, a preprocessor is a program that runs before the actual compilation of the source code. The preprocessor processes special instructions that begin with a โ€œ#โ€ย symbol on the source code before handing it over to the compiler, allowing developers to effectively control the code processing and optimize it for better compilation efficiency.

The โ€˜#โ€™ symbol indicates that, whatever statement starts with #, is going to the preprocessor program, and the preprocessor program will execute this statement.
Examples of some preprocessor directives are: #include, #define, #ifndef, etc.

The preprocessor program processes commands like โ€˜include;โ€™ it is important to note that the โ€˜#โ€™ symbol only indicates the path it will take.

Some common preprocessor directives in C programming include:

    1. #include: Firstly, this directive is used to include header files in the source code. Because the program requires header files that contain function prototypes and macro definitions.
    2. #define: This directive defines macros, which represent constant values or code snippets symbolically. Developers use macros for code reusability and to avoid repetitive code
    3. #ifdef,#ifndef,#else, and #endif: These directives are used for conditional compilation. They help in including or excluding specific blocks of code based on certain conditions.
    4. #error: This directive allows you to generate a compiler error message with a custom error message.
    5. #pragma: This directive instructs the compiler, which might be compiler-specific.

For instance:

#include <stdio.h>

// This is a macro to calculate the square of a number
#define SQUARE(x) ((x) * (x))

// A macro to determine whether a number is even
#define IS_EVEN(x) ((x) % 2 == 0)

// A macro to print a message
#define PRINT_MSG(msg) printf("Message: %s\n", msg)

int main() {
    int num1 = 5;
    int num2 = 7;
    
    printf("Square of %d is %d\n", num1, SQUARE(num1));
    printf("Square of %d is %d\n", num2, SQUARE(num2));
    
    if (IS_EVEN(num1)) {
        PRINT_MSG("num1 is even");
    } else {
        PRINT_MSG("num1 is odd");
    }
    
    if (IS_EVEN(num2)) {
        PRINT_MSG("num2 is even");
    } else {
        PRINT_MSG("num2 is odd");
    }
    
    return 0;
} 

Output:

Square of 5 is 25
Square of 8 is 64
Message: num1 is odd
Message: num2 is even


Hereโ€™s, how itย  works:

The given C program defines three macros: SQUARE(x), IS_EVEN(x), and PRINT_MSG(msg).ย These macros perform specific operations in the main function.

  1. SQUARE(x): This macro is used to calculate the square of a given number x. It simply multiplies x by itself to get the square. For example, if num1 is 5, SQUARE(num1) will expand to (5) * (5) which results in 25.

  2. IS_EVEN(x): This macro is used to check if a given number x is even. It performs a modulo operation with 2 and checks if the result is equal to 0. If it is, the number is even; otherwise, it is odd. For example, if num1 is 5, IS_EVEN(num1) will expand to (5) % 2 == 0, which is false (0), indicating that num1 is odd.

  3. PRINT_MSG(msg): This macro prints a message to the console. It takes a string msg as input and uses printf to display the message along with the string. For example, if you call PRINT_MSG(โ€œHello!โ€), it will print โ€œMessage: Hello!โ€ to the console.

In the main() function, we declare and initialize two integer variables, num1 and num2, with the values 5 and 7, respectively.ย The program then uses the defined macros to calculate and display the squares of num1 and num2, and it also determines whether each number is even or odd, printing the corresponding message to the console.


Important Preprocessor Directives โˆ’

Preprocessor DirectivesDescription
#defineUsed to define a macro
#undefUsed to undefine a macro
#includeUsed to include a file in the source code program
#ifdefUsed to include a section of code if a certain macro is defined by #define
#ifndefUsed to include a section of code if a certain macro is not defined by #define
#ifCheck for the specified condition
#elseAlternate code that executes when #if fails
#endifUsed to mark the end of #if, #ifdef, and #ifndef


Predefined Macros

A macro is a preprocessor directive that defines a symbolic name or a function-like replacement. The preprocessor replaces all occurrences of the symbolic name or function-like macro with the corresponding replacement text before the actual compilation process starts.

ANSI C defines a number of macros. We should not directly modify the predefined macros, although they are available for use in programming.

In conclusion, ย Here are some predefined macros in C programming.

MacroValue
__DATE__ย A string containing the current date.
__FILE__ย A string containing the file name.
__LINE__ย An integer representing the current line number.
__STDC__ย If follows ANSI standard C, then the value is a nonzero integer.
__TIME__ย A string containing the current time.


For instance:

#include <stdio.h>
int main() {
  printf("File :%s\n", __FILE__ );
  printf("Date :%s\n", __DATE__ );
  printf("Time :%s\n", __TIME__ );
  printf("Line :%d\n", __LINE__ );
  printf("ANSI :%d\n", __STDC__ );
}

Output

File :source.c
Date :Jul 29 2022
Time :13:14:28
Line :6
ANSI :1


Preprocessor Operators

Preprocessor directives use special symbols to control code preprocessing before the compiler begins compilation. The preprocessor processes these operators before the compiler starts compiling the code.

Some common preprocessor operators include โˆ’

  • The Macro Continuation (\) Operator: The backslash \ is used to split a long macro definition into multiple lines for better readability. Placing the backslash at the end of a line instructs the preprocessor to continue the macro definition on the next line.ย For example:

    #define LONG_MACRO(a, b, c) \
        do {                     \
            // code here        \
        } while (0) 
  • The Stringize (#) Operator: This Operator allows a macro to convert a macro parameter or argument into a string literal.ย When used before a parameter in the macro definition, it converts the parameterโ€™s value into a string during macro expansion. For example:

    #define STR(x) #x
    
    printf("%s\n", STR(Hello)); // This will print "Hello" 
  • The Token Pasting (##) Operator: This operator concatenates two tokens during macro expansion. It allows you to create new tokens by joining existing ones. For example:

    #define JOIN(a, b) a ## b
    
    int xy = JOIN(10, 20); // This will be replaced with int xy = 1020; 
  • The Defined() Operator: The defined() operator checks if a macro is defined. It returns 1 (true) if you have defined the specified macro, otherwise 0 (false). Programmers commonly use it in conditional compilation. For example:

    #ifdef DEBUG
        // Code for debugging
    #else
        // Code for regular build
    #endif
    
    // Alternatively, you can use the defined() operator
    #if defined(DEBUG)
        // Code for debugging
    #else
        // Code for regular build
    #endif 

These preprocessor operators, in conjunction with other preprocessor directives, allow developers to create more flexible and powerful macros in C, making it easier to manage complex code and improve code organization and maintainability.


Parameterized Macros

Parameterized macros, also known as function-like macros, are macros in C that can take arguments similar to functions. It allow you to define a set of statements that you can use with different arguments throughout the code. You define parameterized macros using the #define directive and enclose one or more parameters in parentheses.

The general syntax of a parameterized macro is:

#define MACRO_NAME(parameter_list) replacement

The macro name is MACRO_NAME, the parameter_list consists of comma-separated parameters (if any), and the replacement is the code that the macro will expand when used.


In the given example, we must define macros with arguments using the #define directive before we can use them. After that enclose the argument list in parentheses and place it immediately after the macro name. Remember not to include spaces between the macro name and open parenthesis.

For instance:

#define MAX(x, y) ((x) > (y) ? (x) : (y))

int main() {
    int a = 10, b = 20, c;
    c = MAX(a, b); // Expands to ((a) > (b) ? (a) : (b))
    printf("The maximum between %d and %d is %d\n", a, b, c);
    return 0;
}

In the above example, MAX is a parameterized macro that takes two arguments x and y, and returns the maximum of the two. When the main() method executes, it effectively calls the macro, seamlessly passing arguments a and b, and preserves the resulting output in the variable c.