Macro Substitution using #define in C

By: Kamini Viewed: 153481 times  Printer Friendly Format    


A definition has the form
   #define name replacement text
It calls for a macro substitution of the simplest kind - subsequent occurrences of the token name will be replaced by the replacement text. The name in a #define has the same form as a variable name; the replacement text is arbitrary. Normally the replacement text is the rest of the line, but a long definition may be continued onto several lines by placing a \ at the end of each line to be continued. The scope of a name defined with #define is from its point of definition to the end of the source file being compiled. A definition may use previous definitions. Substitutions are made only for tokens, and do not take place within quoted strings. For example, if YES is a defined name, there would be no substitution in printf("YES") or in YESMAN.

Any name may be defined with any replacement text. For example

   #define  forever  for (;;)    /* infinite loop */
defines a new word, forever, for an infinite loop.

It is also possible to define macros with arguments, so the replacement text can be different for different calls of the macro. As an example, define a macro called max:

   #define  max(A, B)  ((A) > (B) ? (A) : (B))
Although it looks like a function call, a use of max expands into in-line code. Each occurrence of a formal parameter (here A or B) will be replaced by the corresponding actual argument. Thus the line
   x = max(p+q, r+s);
will be replaced by the line
   x = ((p+q) > (r+s) ? (p+q) : (r+s));
So long as the arguments are treated consistently, this macro will serve for any data type; there is no need for different kinds of max for different data types, as there would be with functions.

If you examine the expansion of max, you will notice some pitfalls. The expressions are evaluated twice; this is bad if they involve side effects like increment operators or input and output. For instance

   max(i++, j++)  /* WRONG */
will increment the larger twice. Some care also has to be taken with parentheses to make sure the order of evaluation is preserved; consider what happens when the macro
   #define square(x)  x * x  /* WRONG */
is invoked as square(z+1).

Nonetheless, macros are valuable. One practical example comes from <stdio.h>, in which getchar and putchar are often defined as macros to avoid the run-time overhead of a function call per character processed. The functions in <ctype.h> are also usually implemented as macros.

Names may be undefined with #undef, usually to ensure that a routine is really a function, not a macro:

   #undef getchar

   int getchar(void) { ... }
Formal parameters are not replaced within quoted strings. If, however, a parameter name is preceded by a # in the replacement text, the combination will be expanded into a quoted string with the parameter replaced by the actual argument. This can be combined with string concatenation to make, for example, a debugging print macro:
   #define  dprint(expr)   printf(#expr " = %g\n", expr)
When this is invoked, as in
   dprint(x/y)
the macro is expanded into
   printf("x/y" " = &g\n", x/y);
and the strings are concatenated, so the effect is
   printf("x/y = &g\n", x/y);
Within the actual argument, each " is replaced by \" and each \ by \\, so the result is a legal string constant.

The preprocessor operator ## provides a way to concatenate actual arguments during macro expansion. If a parameter in the replacement text is adjacent to a ##, the parameter is replaced by the actual argument, the ## and surrounding white space are removed, and the result is re-scanned. For example, the macro paste concatenates its two arguments:

   #define  paste(front, back)  front ## back
so paste(name, 1) creates the token name1.

Most Viewed Articles (in C )

Latest Articles (in C)

Comment on this tutorial