#define Square(x) (x*(x)) [duplicate]

2019-01-29 05:34发布

Possible Duplicate:
square of a number being defined using #define

Can you please explain why the following code outputs "29"?

#define Square(x) (x*(x))

void main()
{
    int x = 5;
    printf("%d", Square(x+3));
}

5条回答
爷、活的狠高调
2楼-- · 2019-01-29 06:09

#define square(X) (x*(x)) is a macro, therefore the compiler replaces the macro with the code:

square(x+3) = x+3*(x+3)

     = 5+3*(5+3) = 5+3*(8) = 29
查看更多
放我归山
3楼-- · 2019-01-29 06:14

Operator precedence. You see, because Square is a macro, not a function, this is what the compiler actually sees:

(x+3*(x+3))

Which operator precedence ends up as:

5 + (3 * (8))

Or 29. To fix the problem:

#define Square(x) ((x)*(x))
查看更多
走好不送
4楼-- · 2019-01-29 06:18

The preprocessor replaced Square(x) with x*(x).

Your code looks like printf("%d", x+3*(x)).

You should use #define Square(x) ((x)*(x)).

查看更多
老娘就宠你
5楼-- · 2019-01-29 06:25

Since macros only do textual replacement you end up with:

x + 3 * (x + 3)

which is 29.

You should absolutely always put macro arguments between parentheses.

#define Square(x) ((x)*(x))

Better yet, use a function and trust the compiler to inline it.


EDIT

As leemes notes, the fact that the macro evaluates x twice can be a problem. Using a function or more complicated mechanisms such as gcc statement expressions can solve this. Here's a clumsy attempt:

#define Square(x) ({    \
    typeof(x) y = (x);  \
    y*y;                \
})
查看更多
我命由我不由天
6楼-- · 2019-01-29 06:25

Please note that although the macro

#define Square(x) ((x)*(x))

seems to solve the problem, it does not. Consider this:

int x = 5;
printf("%d\n", Square(x++));

The preprocessor expands this to:

((x++)*(x++))

which is undefined behavior. Some compilers will evaluate this as

(5 * 5)

which seems as expected in the first place. But x = 7 afterwards, since the increment operator has been applied twice. Clearly not what you were looking for.

For the output, see here: http://ideone.com/9xwyaP

This is why macros* are evil.

(*Macros which tend to be used as a replacement for inline-functions.)

You can fix this in C++ using template functions which can handle all types and in C by specifying a concrete type (since even overloading isn't supported in C, the best you can get is different functions with suffixes):

// C
int SquareI(int x) { return x * x; }
float SquareF(float x) { return x * x; }
double SquareD(double x) { return x * x; }

// C++
template<typename T>
T Square(T x) { return x * x; }

Specifically for GCC, there is another solution, since GCC provides the typeof operator so we can introduce a temporary value within the macro:

#define Square(x) ({ typeof (x) _x = (x); _x * _x; })

Et voila: http://ideone.com/OGu08W

查看更多
登录 后发表回答