C Preprocessor – Macro Expansion

You learned about C preprocessor directives and its components earlier. These directive are of four types – macro expansion, file inclusion, conditional compilation ,and other miscellaneous directives. The macro expansion is the most common and popular C preprocessor directives.

Before you begin, learn a bit about the preprocessor directives. If you are familiar with the concept, skip ahead.

A macro is a small piece of code or constant value that is replaced with C source code before the execution of a C program. This concept is same as inline codes defined using the keyword inline.

What is a macro expansion?

To understand the concept of macro expansion, consider an example program code given below. The program used the #define directive.

#include <stdio.h>
#include <stdlib.h>

#define LENGTH 10
#define BREADTH 20

int main()
{
    int area_rectangle = 0;

    area_rectangle = LENGTH * BREADTH;

    printf("Area of Rectangle = %d\n",area_rectangle);

    system("PAUSE"); 
    return 0;
}

Output

Area of Rectangle = 200

The LENGTH and BREADTH are called the macro templates. The values 10 and 20 are called macro expansions.

When the program run and if the C preprocessor sees an instance of a macro within the program code, it will do the macro expansion. It replaces the macro template with the value of macro expansion.

The #define directive is a good way of declaring constant compared to a constant or a variable value. To change the constant, you must change it in all place in source code individually. The macro on the other hand only requires you to change the value of the #define directive.

Another advantage of macro expansion is that it is much faster than the variables or constants.

Usage of #define Directive

The #define directive is not only used to label a constant, but also other types of statements. The following program that demonstrates other possible usage of a #define directive.

#include <stdio.h>
#include <stdlib.h>

#define AND && // define an operator
#define OR ||

#define CONDITION1 (p > 10) AND (q < 100) // define a condition
#define CONDITION2 (q > 100)

#define STATEMENT1 printf("p is greater than 10\n");
#define STATEMENT2 printf("q is greater than 100\n"); //print statements

int main()
{
    int p,q;

    p = 13;
    q = 10;

    if(CONDITION1)
    {

        STATEMENT1

    }
    else if(CONDITION2)
    {

        STATEMENT2

    }

    system("PAUSE"); 
    return 0;
}

Output

p is greater than 10

In the above program, we defined three different types of macro templates – operators, conditions, and statements. In other words, all elements of a program are suitable for  macro expansion. You can use operators, replace conditions or execute any code, the preprocessor will replace it into a source code (macro expansion).

It is not a good practice to use large piece codes for the macro expansion. The next section is about complex macros that do exactly the same.

Macros with Arguments

The complex macros take arguments like functions and it looks like a function. But there is a big difference between complex macro and a C function. See the example below.

#include <stdio.h>
#include <stdlib.h>

#define SQUARE(x) (x * x)

int main()
{

    int n;
    int result;

    n = 5;
    result = 0;

    result = SQUARE(n);

    printf("Result = %d\n",result);

    system("PAUSE"); 
    return 0;

}

Output3

Result = 25

The macro template takes argument x which is a value of the appropriate type(integer for multiplication). Whenever the C preprocessor sees SQUARE(x) in the program source code, it replaces it with ( x * x).

The x in the SQUARE(x) is an argument. So the macro expansion of SQUARE(n) becomes (n * n) where n has a value assigned to it.

Common Mistakes while using #define

Mistakes happen when you write your programs, especially when you are new to C programming. A list of common mistakes while using a #define directive is given below.

  • Forgetting the # sign that results in a compiler error
  • Not choosing a meaningful name for macro templates
  • Using too many #define directives
  • Using { } braces instead of ( ) in complex macros.
  • Leaving a gap between macros –  AREA    (x)    (x * x). This will result in compiler error.

In the next section, we will discuss about file inclusion preprocessor directives.