5

可能重复:
使用#define 定义的数字的平方

你能解释一下为什么下面的代码输出“29”吗?

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

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

5 回答 5

24

由于宏仅进行文本替换,因此您最终会得到:

x + 3 * (x + 3)

这是29。

您绝对应该始终将宏参数放在括号之间。

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

更好的是,使用一个函数并相信编译器会内联它。


编辑

正如 leemes 所指出的,宏计算x两次的事实可能是一个问题。使用函数或更复杂的机制(例如 gcc 语句表达式)可以解决此问题。这是一个笨拙的尝试:

#define Square(x) ({    \
    typeof(x) y = (x);  \
    y*y;                \
})
于 2013-02-02T14:21:54.803 回答
8

请注意,虽然宏

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

似乎解决了问题,它没有。考虑一下:

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

预处理器将其扩展为:

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

这是未定义的行为。一些编译器会将其评估为

(5 * 5)

这似乎一开始就如预期的那样。但x = 7之后,由于增量运算符已被应用了两次。显然不是你要找的。

有关输出,请参见此处:http: //ideone.com/9xwyaP

这就是为什么宏*是邪恶的。

(*宏往往被用作内联函数的替代品。)

您可以在 C++ 中使用可以处理所有类型的模板函数来解决此问题,在 C 中通过指定具体类型来解决此问题(因为 C 中甚至不支持重载,所以您能得到的最好的方法是带有后缀的不同函数):

// 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; }

特别是对于 GCC,还有另一种解决方案,因为 GCC 提供了typeof运算符,所以我们可以在宏中引入一个临时值:

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

等等瞧:http: //ideone.com/OGu08W

于 2013-02-02T14:32:37.817 回答
7

运算符优先级。你看,因为 Square 是一个宏,而不是一个函数,这是编译器实际看到的:

(x+3*(x+3))

哪个运算符优先级最终为:

5 + (3 * (8))

或 29. 解决问题:

#define Square(x) ((x)*(x))
于 2013-02-02T14:23:38.427 回答
4

预处理器将 Square(x) 替换为 x*(x)。

您的代码看起来像printf("%d", x+3*(x)).

你应该使用#define Square(x) ((x)*(x)).

于 2013-02-02T14:23:03.970 回答
1

#define square(X) (x*(x))是一个宏,因此编译器将宏替换为以下代码:

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

     = 5+3*(5+3) = 5+3*(8) = 29
于 2013-02-02T14:28:10.113 回答