Preprocessor Directives / Macros in Detail - BunksAllowed

BunksAllowed is an effort to facilitate Self Learning process through the provision of quality tutorials.

Community

Preprocessor Directives / Macros in Detail

Share This

Macro Functions


A more advanced use of macros is also permitted by the preprocessor. This involves macros which accept parameters and hand back values. This works by defining a macro with some dummy parameter, say x. For example: a macro which is usually defined in one of the standard libraries is abs() which means the absolute or unsigned value of a number. It is defined below:

#define ABS(x) ((x) < 0) ? -(x) : (x)
  
The result of this is to give the positive (or unsigned) part of any number or variable. This would be no problem for a function which could accept parameters, and it is, in fact, no problem for macros. Macros can also be made to take parameters. Consider the ABS() example. If a programmer were to write ABS(4) then the preprocessor would substitute 4 for x. If a program read ABS(i) then the preprocessor would substitute i for x and so on. (There is no reason why macros can't take more than one parameter too. The programmer just includes two dummy parameters with different names. See the example listing below.) Notice that this definition uses a curious operator which belongs to C:

<test> ? <true result> : <false result>
  
This is like a compact way of writing an if..then..else statement, ideal for macros. But it is also slightly different: it is an expression which returns a value, where as an if..then..else is a statement with no value. Firstly the test is made. If the test is true then the first statement is carried out, otherwise the second is carried out. As a memory aid, it could be read as:

if <test> then <true result> else <false result>
  
Do not be confused by the above statement which is meant to show what a programmer might think. It is not a valid C statement. C can usually produce much more efficient code for this construction than for a corresponding if-else statement.


When and when not to use macros with parameters


It is tempting to forget about the distinction between macros and functions, thinking that it can be ignored. To some extent this is true for absolute beginners, but it is not a good idea to hold on to. It should always be remembered that macros are substituted whole at every place where they are used in a program: this is potentially a very large amount of repetition of code. The advantage of a macro, however, is speed. No time is taken up in passing control over to a new function, because control never leaves the home function when a macro is used: it just makes the function a bit longer. There is a limitation with macros though. Function calls cannot be used as their parameters, such as ABS(function()) has no meaning. Only variables or number constants will be substituted. Macros are also severely restricted in complexity by the limitations of the preprocessor. It is simply not viable to copy complicated sequences of code all over programs.

Choosing between functions and macros is a matter of personal judgement. No simple rules can be given. In the end (as with all programming choices) it is experience which counts towards the final ends. Functions are easier to debug than macros, since they allow us to single step through the code. Errors in macros are very hard to find, and can be very confusing.

#include <stdio.h> #define STRING1 "A macro definition\n" #define STRING2 "must be all on one line!!\n" #define EXPRESSION 1 + 2 + 3 + 4 #define EXPR2 EXPRESSION + 10 #define ABS(x) ((x) < 0) ? -(x) : (x) #define MAX(a,b) (a < b) ? (b) : (a) #define BIGGEST(a,b,c) (MAX(a,b) < c) ? (c) : (MAX(a,b)) /************************************************************/ main () /* No #definitions inside functions! */ { printf (STRING1); printf (STRING2); printf ("%d\n",EXPRESSION); printf ("%d\n",EXPR2); printf ("%d\n",ABS(-5)); printf ("Biggest of 1 2 and 3 is %d",BIGGEST(1,2,3)); }

More Preprocessor Commands


#undefThis undefines a macro, leaving the name free. 

#if This is followed by some expression on the same line. It allows conditional compilation. It is an advanced feature which can be used to say: only compile the code between #if and #endif if the value following #if is true, else leave out that code altogether. This is different from not executing code--the code will not even be compiled.

#ifdef This is followed by a macro name. If that macro is defined then this is true.

#ifndef This is followed by a macro name. If that name is not defined then this is true.

#else This is part of an #if, #ifdef, #ifndef preprocessor statement.

#endif This marks the end of a preprocessor statement.

#line Has the form:

i.e. #line constant filename: This is for debugging mainly. This statement causes the compiler to believe that the next line is line number (constant) and is part of the file (filename).

#error This is a part of the proposed ANSI standard. It is intended for debugging. It forces the compiler to abort compilation.


#define SOMEDEFINITION 6546 #define CHOICE 1 /* Choose this before compiling */ /***********************************************************/ #if (CHOICE == 1) #define OPTIONSTRING "The programmer selected this" #define DITTO "instead of .... " #else #define OPTIONSTRING "The alternative" #define DITTO "i.e. This! " #endif /***********************************************************/ #ifdef SOMEDEFINITION #define WHATEVER "Something was defined!" #else #define WHATEVER "Nothing was defined" #endif /************************************************************/ main () { printf (OPTIONSTRING); printf (DITTO); }

Happy Exploring!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.