How to use #define Macros in C

#define macro in c

Macros are a type of pre-processor. Pre-processors begin with the “#” symbol and are also called  directives. They are of great convenience to the programmers and are used frequently in most of the C programs. They can be placed anywhere in the program. But they are usually placed at the beginning of the program before any variable/function declarations.

The first step of a C compilation process is the pre-processing. You can read about the C Compilation Process here. The output of the pre-processing stage is a “.i” file.

Preprocessing does the following things:

  1. Evaluate all Preprocessor Directives.
  2. Remove the Comments

Types of pre-processor directives

There are many types of preprocessors in C.

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

The following video gives a good explaination of preprocessors and the different types. In this post, we will cover Macros.

Macro Expansion

Macros are also called #define in C. That is because, to define a macro, we use the statement “#define

Let us look at macro expansion through an example. Consider the following example. Assume that a class has 30 students. And the program is written to calculate the average mark obtained by each student.

int main ()

{
   int avg = 0;
   int sub1_arr[30] = {24,54,74,14,....};   // upto 30 students
   int sub2_arr[30] = {43,44,32,58......};  // upto 30 students

   for (int i= 0;i < 30;i++)
   {
      avg = (sub1_arr[i] + sub2_arr[i])/2;
      printf ("Student %d has an average of %d\n",i+1,avg);
   }
   return 0;
}

Using Macros in C

The above code prints the average of all the 30 students. As the number of students in the class can vary by time, assume there are ‘x’ new students joining the class, every month. In such situations,

  • we will have to manually replace the value ’30’ everywhere in the program. Missing even one place will result in misbehavior.
  • Moreover, the number ’30’ is not intuitive. Imagine a larse code where such numbers appear frequently. It will be a nightmare for the people making changes to the code or maintaining it.

And, wouldn’t it be good if we could give a name to this number? Then, then name becomes more intuitive and is easily understood.

This is where the Macros come in. They let us define names and give values to those names. Now, we can use these names in the program instead of the values. Let’s look at an example that makes use of a macro and then see the benefits of it.

 #define NO_OF_STUDENTS 40

int main()
{
   int avg = 0;
   int sub1_arr[NO_OF_STUDENTS] = {24,54,74,14,....};   // upto 40 students
   int sub2_arr[NO_OF_STUDENTS] = {43,44,32,58......};  // upto 40 students

   for (int i= 0;i < NO_OF_STUDENTS;i++)
   {
      avg = (sub1_arr[i] + sub2_arr[i])/2;
      printf ("Student %d has an average of %d\n",i+1,avg);
   }
   return 0;
}

In the above code, what we have is a name for the value, for the number of students. Now, anytime the number of students change, we just have to make the change at one place and it will be reflected everywhere. Thus, we avoid the problem of missing out update at some places and the code also becomes to maintain and work upon.

Such statements are often called as macro definitions or simply macros. During pre-processing, the program replaces all NO_OF_STUDENTS by the number defined with it.

The following video will help you understand Macros with the help of its use in a program.

 

In the following video, you can see the preprocessed file:

Let us consider another example.

#define PI 3.141

int main()
{
   float radius = 3.3; float area = 0;
   area = PI*radius*radius;
   printf("The area of circle is %f\n", area);
   return 0;
}

In the above program, since the value of PI is universally same, it can be defined with the help of pre-processor.

The program replaces the instances of the word PI in program by the number 3.141. Today you may limit the value of pi to 3.141, but might want to change it tomorrow to 3.141592653589 for more accuracy. Macros make it easy to replace the required value. Whenever the program sees a #define directive, it searches for the macro template over the entire program, and replaces with the physical value there. Generally for macros, use of Capital Letters makes programmers easy to pick while going through the program.

Macros with Arguments in C

We can also pass arguments to macros. Consider the example below:

#define AREA_OF_CIRCLE(r) (3.141*r*r) 

main() 
{ 
   float ra = 5.7; 
   printf("The Area of circle with radius %f is %f\n", r, AREA_OF_CIRCLE(ra)); 
}

In the above program, the preprocessor finds the instances of AREA_OF_CIRCLE(r) and expands it by its formula (3.141*r*r). This makes some simple calculations to be expressed in one single line. The benefit of doing this is that if, for some reason, you want to update the formula for the calculation, you can just change it in the line where you defined it.

Note:

    1. Do not leave a blank space while defining a macro and its argument. Eg: AREA_OF_CIRCLE (r) (3.14*r*r) – This will result in a wrong interpretation. No space in between AREA_OF_CIRCLE and (r).
    2. Enclose the Macro expansions within brackets.
#define SQUARE(n) n*n

main()
{
   int i;
   i = 64/SQUARE(4);
   printf("i=%d",i);
}

The output expected from this program is i = 4, but the output would be i = 64.

The pre-processed output of the expansion is as follows:

main()
{
   int i;
   i = 64/4*4;
   printf("i=%d",i);
}

The statement i = 64/4*4; is evaluated as

64/4*4 = 16*4 = 64

Always enclose the expansion is brackets, as #define SQUARE(n) (n*n)

The following video will help you understand better. It shows the expansion in a program.

 

Split Macros in C into multiple line

We can split Macros in C into multiple lines if the expansion has multiple statements

#define HORLINE for( i = 0 ; i < 79 ; i++ ) \
                   printf ( "%c", 196 ) ;
main( )
{
   int i;
   clrscr();
   HORLINE
}

This program draws a horizontal line on the screen.

Why not use a “const” Variable instead of Macros?

The reasons for this are:

  1. The simple reason for this is that #define Macros are replaced in the code during preprocessing. But const variables are part of the final compiled program.
  2. Since #define macros are replaced during run time, they do not occupy additional memory which the const variables will occupy.

 

Want to learn more about C and Embedded C? Follow the tutorial Series on YouTube – Master C and Embedded C Programming

Join the Course on Udemy to get a Certificate of Completion for C and Embedded C Programming.

Sharing is Caring!!

Leave a Reply

Your email address will not be published.