10.4 Parameterized Macros

I l @ ve RuBoard

So far we have discussed only simple #define s or macros. Macros can take parameters. The following macro computes the square of a number:

 #define SQR(x)  ((x) * (x))     /* Square a number */ 

There can be no space between the macro name ( SQR in this example) and the open parenthesis.

When used, the macro replaces x with the text of its argument. SQR(5) expands to ((5) * (5)). It is a good rule always to put parentheses around the parameters of a macro. Example 10-7 illustrates the problems that can occur if this rule is not followed:

Example 10-7. sqr/sqr.cpp
 #include <iostream> #define SQR(x) (x * x) int main(  ) {     int counter;    // counter for loop     for (counter = 0; counter < 5; ++counter) {         std::cout << "x " << (counter+1) <<                  " x squared " << SQR(counter+1) << '\n';     }     return (0); } 

Question 10-5: What does the above program output? (Try running it on your machine.) Why did it output what it did? (Try checking the output of the preprocessor.)

The keep-it-simple system of programming prevents us from using the increment ( ++ ) and decrement ( -- ) operators except on a line by themselves . When used in an expression, they cause side effects, and this can lead to unexpected results, as illustrated in Example 10-8.

Example 10-8. sqr-i/sqr-i.cpp
 #include <iostream> #define SQR(x) ((x) * (x)) int main(  ) {     int counter;    /* counter for loop */     counter = 0;     while (counter < 5)         std::cout << "x " << (counter+1) <<                  " x squared " << SQR(++counter) << '\n';     return (0); } 

Why does this not produce the expected output? How much does the counter go up each time?

In the program shown in Example 10-8, the SQR(++counter) is expanded to ((++counter) * (++counter)) in this case. The result is that counter goes up by 2 each time through the loop. The actual result of this expression is system-dependent.

Question 10-6: Example 10-9 tells us we have an undefined variable, but our only variable name is counter . Why?

Example 10-9. rec/rec.cpp
 #include <iostream> #define RECIPROCAL (number) (1.0 / (number)) int main(  ) {     float   counter;     for (counter = 0.0; counter < 10.0;           counter += 1.0) {         std::cout << "1/" << counter << " = " <<                    RECIPROCAL(counter) << "\n";      }     return (0); } 

10.4.1 The # Operator

The # operator is used inside a parameterized macro to turn an argument into a string. For example:

 #define STR(data) #data STR(hello) 

This code generates:

 "hello" 

For a more extensive example of how to use this operator, see Chapter 27.

10.4.2 Parameterized Macros Versus Inline Functions

In most cases, to avoid most of the traps caused by parameterized macros, it is better to use inline functions. But there are cases where a parameterized macro may be better than an inline function. For example, the SQR macro works for both float and int data types. We'd have to write two inline functions to perform the same functions, or we could use a template function. (See Chapter 24.)

 #define SQR(x) ((x) * (x))  // A parameterized macro // Works, but is dangerous // Inline function to do the same thing inline int sqr(const int x) {     return (x * x); } 
I l @ ve RuBoard


Practical C++ Programming
Practical C Programming, 3rd Edition
ISBN: 1565923065
EAN: 2147483647
Year: 2003
Pages: 364

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net