可能重复:
使用#define 定义的数字的平方
你能解释一下为什么下面的代码输出“29”吗?
#define Square(x) (x*(x))
void main()
{
int x = 5;
printf("%d", Square(x+3));
}
可能重复:
使用#define 定义的数字的平方
你能解释一下为什么下面的代码输出“29”吗?
#define Square(x) (x*(x))
void main()
{
int x = 5;
printf("%d", Square(x+3));
}
由于宏仅进行文本替换,因此您最终会得到:
x + 3 * (x + 3)
这是29。
您绝对应该始终将宏参数放在括号之间。
#define Square(x) ((x)*(x))
更好的是,使用一个函数并相信编译器会内联它。
编辑
正如 leemes 所指出的,宏计算x
两次的事实可能是一个问题。使用函数或更复杂的机制(例如 gcc 语句表达式)可以解决此问题。这是一个笨拙的尝试:
#define Square(x) ({ \
typeof(x) y = (x); \
y*y; \
})
请注意,虽然宏
#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
运算符优先级。你看,因为 Square 是一个宏,而不是一个函数,这是编译器实际看到的:
(x+3*(x+3))
哪个运算符优先级最终为:
5 + (3 * (8))
或 29. 解决问题:
#define Square(x) ((x)*(x))
预处理器将 Square(x) 替换为 x*(x)。
您的代码看起来像printf("%d", x+3*(x))
.
你应该使用#define Square(x) ((x)*(x))
.
#define square(X) (x*(x))
是一个宏,因此编译器将宏替换为以下代码:
square(x+3) = x+3*(x+3)
= 5+3*(5+3) = 5+3*(8) = 29