Chinaunix首页 | 论坛 | 博客
  • 博客访问: 966636
  • 博文数量: 184
  • 博客积分: 10030
  • 博客等级: 上将
  • 技术积分: 1532
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-27 18:32
文章分类

全部博文(184)

文章存档

2009年(1)

2008年(63)

2007年(39)

2006年(79)

2005年(2)

我的朋友

分类: C/C++

2007-11-14 12:50:51

   < Day Day Up >   

Using Arguments with #define

By using arguments, you can create function-like macros that look and act much like functions. A macro with arguments looks very similar to a function because the arguments are enclosed within parentheses. Function-like macro definitions have one or more arguments in parentheses, and these arguments then appear in the replacement portion, as shown in [Figure 16.2]

Figure 16.2. Parts of a function-like macro definition.

graphics/16fig02.gif


Here's a sample definition:


#define SQUARE(X) X *X


It can be used in program like this:


z = SQUARE(2);


This looks like a function call, but it doesn't necessarily behave identically. [Listing 16.2] illustrates using this and a second macro. Some of the examples also point out possible pitfalls, so read them carefully.

Listing 16.2. The mac_arg.c Program
/* mac_arg.c -- macros with arguments */

#include 

#define SQUARE(X) X*X

#define PR(X)   printf("The result is %d.\n", X)

int main(void)

{

    int x = 4;

    int z;



    printf("x = %d\n", x);

    z = SQUARE(x);

    printf("Evaluating SQUARE(x): ");

    PR(z);

    z = SQUARE(2);

    printf("Evaluating SQUARE(2): ");

    PR(z);

    printf("Evaluating SQUARE(x+2): ");

    PR(SQUARE(x+2));

    printf("Evaluating 100/SQUARE(2): ");

    PR(100/SQUARE(2));

    printf("x is %d.\n", x);

    printf("Evaluating SQUARE(++x): ");

    PR(SQUARE(++x));

    printf("After incrementing, x is %x.\n", x);



    return 0;

}


The SQUARE macro has this definition:


#define SQUARE(X) X*X


Here, SQUARE is the macro identifier, the X in SQUARE(X) is the macro argument, and X*X is the replacement list. Wherever SQUARE(x) appears in[Listing 16.2], it is replaced by x*x. This differs from the earlier examples in that you are free to use symbols other than x when you use this macro. The x in the macro definition is replaced by the symbol used in the macro call in the program. Therefore, SQUARE(2) is replaced by 2*2, so the x really does act as an argument.

However, as you will soon see, a macro argument does not work exactly like a function argument. Here are the results of running the program. Note that some of the answers are different from what you might expect. Indeed, your compiler might not even give the same answer as what's shown here for the next-to-last line:


x = 4

Evaluating SQUARE(x): The result is 16.

Evaluating SQUARE(2): The result is 4.

Evaluating SQUARE(x+2): The result is 14.

Evaluating 100/SQUARE(2): The result is 100.

x is 4.

Evaluating SQUARE(++x): The result is 30.

After incrementing, x is 6.


The first two lines are predictable, but then you come to some peculiar results. Recall that x has the value 4. This might lead you to expect that SQUARE(x+2) would be 6*6, or 36, but the printout says it is 14, which sure doesn't look like a square to us! The simple reason for this misleading output is the one we have already stated—the preprocessor doesn't make calculations; it just substitutes strings. Wherever the definition shows an x, the preprocessor substitutes the string x+2. Therefore,


x*x


becomes


x+2*x+2


The only multiplication is 2*x. If x is 4, this is the value of this expression:


4+2*4+2 = 4 + 8 + 2 = 14


This example pinpoints an important difference between a function call and a macro call. A function call passes the value of the argument to the function while the program is running. A macro call passes the argument token to the program before compilation; it's a different process at a different time. Can the definition be fixed to make SQUARE(x+2) yield 36? Sure. You simply need more parentheses:


#define SQUARE(x)  (x)*(x)


Now SQUARE(x+2) becomes (x+2)*(x+2), and you get the desired multiplication as the parentheses carry over in the replacement string.

This doesn't solve all the problems, however. Consider the events leading to the next output line:


100/SQUARE(2)


becomes


100/2*2


By the laws of precedence, the expression is evaluated from left to right: (100/2)*2 or 50*2 or 100. This mix-up can be cured by defining SQUARE(x) as follows:


#define SQUARE(x)  (x*x)


This produces 100/(2*2), which eventually evaluates to 100/4, or 25.

To handle both of the previous two examples, you need this definition:


#define SQUARE(x)  ((x)*(x))


The lesson here is to use as many parentheses as necessary to ensure that operations and associations are done in the right order.

Even these precautions fail to save the final example from grief:


SQUARE(++x)


becomes


++x*++x


and x gets incremented twice, once before the multiplication and once afterward:


++x*++x = 5*6 = 30


Because the order of operations is left open, some compilers render the product 6*5. Yet other compilers might increment both terms before multiplication, yielding 6*6. In all these cases, however, x starts with the value 4 and ends up with the value 6, even though the code looks as though x was incremented just once.

The simplest remedy for this problem is to avoid using ++x as a macro argument. In general, don't use increment or decrement operators with macros. Note that ++x would work as a function argument because it would be evaluated to 5, and then the value 5 would be sent to the function.

 

   < Day Day Up >   
阅读(711) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~