0

当我定义这个宏时:

#define SQR(x) x*x

让我们说这个表达式:

SQR(a+b)

此表达式将被宏替换,如下所示:

a+b*a+b

但是,如果我++在表达式之前放置一个运算符:

++SQR(a+b)

现在的表情是什么样的?这是++放置在 SQR 参数的每个部分之前吗?像这样:

++a+b*++a+b

这里我给出一个简单的程序:

#define SQR(x) x*x
int a, k = 3;
a = SQR(k+1) // 7
a = ++SQR(k+1) //9
4

5 回答 5

5

在定义宏时,您基本上总是希望将宏参数放在括号中以防止在第一个示例中出现那种奇怪的行为,并将结果放在括号中,以便可以安全地使用它而不会产生副作用。使用

#define SQR(x) ((x)*(x))

使得SQR(a+b)展开到((a+b)*(a+b))在数学上是正确的(不像a+b*a+b,它等于 ab+a+b)。

在宏之前或之后放置东西不会进入宏。++SQR(x)在您的++x*x示例中也是如此。

请注意以下事项:

int a=3, b=1;
SQR(a+b) // ==> a+b*a+b = 3+1*3+1 = 7
++SQR(a+b) // ==> ++a+b*a+b ==> 4 + 1*4 + 1 = 9
           // since preincrement will affect the value of a before it is read.

您会看到++SQR(a+b)似乎增加了 2,因为在a我读取任一时间之前预增量开始,即a递增,然后使用两次,因此结果比预期的高 2。

注意正如@JonathanLeffler 指出的那样,后一个调用会调用未定义的行为;评估不保证从左到右进行。它可能会在不同的编译器/操作系统上产生不同的结果,因此永远不应依赖它。

于 2012-09-20T04:31:30.690 回答
1

对于 C++,定义此宏的正确方法是不使用宏,而是使用:

template<typename T> static T SQR( T a ) { return a*a; }

这将纠正一些宏出错的可怕情况:

例如:

SQR(++a); 

函数形式++a将被评估一次。在宏形式中,当您在序列点之间多次修改和读取值时,您会得到未定义的行为(至少对于 C++)

于 2012-09-20T04:47:12.807 回答
0

宏定义只是替换代码,因此通常最好放在括号中,否则代码可能会以您不想要的方式替换。

因此,如果您将其定义为:

#define SQR(x) ((x)*(x))

然后

++SQR(a+b) = ++((a+b)*(a+b))

于 2012-09-20T04:36:30.543 回答
0

在您的示例中,++SQR(a+b)应扩展为++a+b*a+b. 因此,如果 a == 3 和 b == 1如果编译器从左到右评估它,
您将得到答案。9

但是您的陈述++SQR(3+1)是不正确的,因为它将被扩展为++3+1*3+1where++3无效。

于 2012-09-20T04:42:12.540 回答
0

在您的预处理器中,它的计算结果为 ++a+b*a+b。正确的方法是在每个术语和整个事物周围加上括号,例如:

#define SQR(x)  ((x)*(x))
于 2012-09-20T04:45:24.717 回答