为什么这个宏给出输出144而不是121?
#include<iostream>
#define SQR(x) x*x
int main()
{
int p=10;
std::cout<<SQR(++p);
}
使用此宏进行平方的方法有两个问题:
首先,对于参数++p
,增量操作执行两次。这当然不是故意的。 (作为一般经验法则,不要在“一行”中做几件事。将它们分成更多的陈述。)它甚至没有停止递增两次:这些增量的顺序没有定义,因此没有保证此操作的结果!
其次,即使你没有++p
作为参数,你的宏中仍然存在一个错误!考虑输入1 + 1
。预计产量为4
。 1+1
没有副作用,所以它应该没问题,不应该吗?不,因为SQR(1 + 1)
转换为1 + 1 * 1 + 1
,其评估为3
。
要至少部分修复此宏,请使用括号:
#define SQR(x) (x) * (x)
总之,你应该简单地用一个函数替换它(添加类型安全!)
int sqr(int x)
{
return x * x;
}
您可以考虑将其作为模板
template <typename Type>
Type sqr(Type x)
{
return x * x; // will only work on types for which there is the * operator.
}
并且你可以添加一个constexpr
(C ++ 11),如果你打算在模板中使用正方形,这是很有用的:
constexpr int sqr(int x)
{
return x * x;
}
这是预处理器宏的缺陷。问题是表达式++p
被使用了两次,因为预处理器只是简单地用字体替换宏“调用”。
那么编译器在宏扩展后看到了什么
std::cout<<++p*++p;
根据宏的不同,如果不小心将括号放在需要的位置,也可能会出现运算符优先级问题。
以宏等为例
// Macro to shift `a` by `b` bits
#define SHIFT(a, b) a << b
...
std::cout << SHIFT(1, 4);
这将导致代码
std::cout << 1 << 4;
这可能不是想要或预期的。
如果您想避免这种情况,请改用内联函数:
inline int sqr(const int x)
{
return x * x;
}
这有两件事情要做:首先是表达式++p
只会被评估一次。另一件事是,现在你不能将除int
值以外的任何东西传递给函数。使用预处理器宏,您可以像SQR("A")
一样“调用”它,而预处理器在您从编译器获取(有时)隐含错误时并不在意。
此外,标记为inline
,编译器可以完全跳过实际的函数调用,并将(正确的)x*x
直接放在调用的位置,从而使其像宏扩展一样“优化”。
因为您使用的是未定义的行为。扩展宏时,您的代码变为:
std::cout<<++p*++p;
在同一语句中多次使用相同变量的递增/递减运算符是未定义的行为。
因为SQR(++ p)扩展为++ p * ++ p,它在C / C ++中具有未定义的行为。在这种情况下,它在评估乘法之前递增p两次。但你不能依赖它。使用不同的C / C ++编译器可能是121(甚至42)。