Wednesday, February 24, 2016

C Preprocessor Directives and Macros

C pre-processor directives help us to modify the program text before it is compiled. Basically, C pre-processors directives have the capability of simple text substitution tool, so that you can modify parts of program before it's actually compiled. We've already used few of the C pre-processors in the examples discussed in different chapters of this C programming tutorial. One of them is #include pre-processor directive which includes a header file into the program. Apart from including header files, there are other C pre-processor directives also which allow us to define a constant, write macros etc. C pre-processor comes in handy if you want some part of your code to be compiled depending on some condition. It is also known as conditional compilation.

Macro Definition in C

The macro can be used to define code that would be in-lined to the source code before compilation. The macro can be of two types, object likes (macro without arguments) and function like (macro with arguments or parameterized macros). Object like macro does not take any argument where function type macro resembles a function as it takes arguments like functions.

Example of #undef and #define Macros in C

  1. #include<stdio.h>
  2. #define A 2
  3. void main()
  4. {
  5. printf("First value: %d\n", A);
  6. #undef A
  7. #define A 3
  8. printf("Second value: %d", A);
  9. }
The above program will generate the output as "First value: 2" and in the second line "Second value: 3". At first, we defined the value of 'A' as 2 and, after first 'printf', the'#undef' code will undefine the value of 'A' and the following 'define' statement will define it again with value 3. Please note that all these happens before actual compilation of program

#include pre-processor Directive

We have already used '#include' directive a number of times in different examples discusses so far. This pre-processor is used for file inclusion. Using '#include' pre-processor causes the definition of header file to be included in the source file. That way when we are using functions from different header files, like 'printf', program knows what these functions do. It is also useful for inclusion of the user defined header files as well. There are two ways to write'#include' directive.
  1. #include <header_file.h>
  2. or,
  3. #include "header_file.h"
Both of the above statements include the header file specified as part of it, the only difference is in the search path of the header file. If we use angular brackets (< >), then the header file is searched in the system defined path. In the case of double quotation (" "), the header file will be searched first in the current path, i.e. the path where the source file is. Mainly we use angular brackets when including a system provided header file and double quotes are used when including header files written by the programmer.

Macro Function/Parameterized Macros

The macros we have used until now are without any arguments. Macros can have arguments too, like the functions. Such macro definitions are called parameterized macros. A simple example of parameterized macro definition is given below

Parameterized Macro Example in C

  1. #include<stdio.h>
  2. #define SQUARE(x) (x * x)
  3. void main()
  4. {
  5. int i = 3;
  6. int sq = SQUARE(i);
  7. printf("Square value: %d\n", sq);
  8. }
This program will generate output as "Square value: 9". But there is something different in parameterized macro in comparison with functions in C. Macro definitions are in-lined in the program, which means the definition of the macro 'SQUARE'will be replaced in the program before compilation. So, the statement
  1. int sq = SQUARE(i);
will be replaced by
  1. int sq = (i * i);
The advantage of using the macro is that it does not depend on the type of the arguments and also the macro function is in-lined. It is also a disadvantage of macro. Consider the above macro function 'SQUARE', and we use it in the program as SQUARE( i + 1). We know that value of 'i' is 3 and so the expected output should be 16. But the reality is quite different. As the macro is inlined, SQUARE(i + 1) will be replaced by (i + 1 * i + 1). Now the precedence of operator '+' is lower than '*'. So the statement will be treated as (i + (1 * i ) + 1) and will generate output 7. One way to avoid this, is by using parenthesis in macro, like
  1. #define SQUARE(x) ((x) * (x))
or where we used the macro, like
  1. int sq = SQUARE((i + 1));

Multi-Lined Macros

The macro functions can be multi line statements also. To write multiline macro, each line must be followed by a backslash ("\") except the last line. A multiline macro looks like the following

Multiline Macro Example in C

  1. #define ABC(n)\
  2. for(i = 0; i < n; i++)\
  3. {
  4. printf("%d\n", i);\
  5. }

No comments: