请给我完整的说明。 第一个代码段在增量运算符之前具有“函数调用”(宏调用),第二个代码段在增量运算符之后具有“函数调用”。
#include <stdio.h>
#define square(x) x*x
int main()
{
int a,b=3;
a=square (b)++;
printf("%d%d",a,b);
return 0;
}
输出:
124
为什么这里返回124
#include <stdio.h>
#define square(x) x*x
int main()
{
int a,b=3;
a=square (b++);
printf("%d%d",a,b);
return 0;
}
输出:
125
还有125个?
答案 0 :(得分:3)
要记住的是,宏提供了预处理器令牌的简单替换。特别是,他们可能会多次评估自己的论点,并且如果没有括号的保护,他们可能会产生意想不到的重新关联。
在第一个示例中,我们有
a=square (b)++;
这扩展为:
a=b*b++;
这实际上是未定义的行为,因为b
和b++
未排序,并且b++
修改了b
。在您的情况下,您看到a
和b
的12和4,因此b
的第一个值似乎正在获取递增的值,因此得到4 * 3,但是您不能指望这种行为。 b
的最终值是4,因为它增加了一次。
在第二个示例中,我们有:
a=square (b++);
这扩展为:
a=b++*b++;
这也是未定义的行为。在您的情况下,看来您得到的是4 * 3(或3 * 4),但是同样,您不能指望这种行为。 b
的最终值是5,因为它增加了两次,但这也是未定义的行为。
答案 1 :(得分:0)
除了汤姆的答案(它解释了正在发生的事情)之外,这里还提供了一个示例,该示例说明了如何定义用于安全地对数字进行平方的宏:
#define SQR(x) ( \
{ \
__auto_type x_ = (x); \
\
x_ * x_; \
} \
)
它的外观仅为x
,因此不会对其进行两次评估。而是使用副本x_
。请注意,在宏中创建的变量可能与在调用宏的函数中创建的其他变量冲突。为了避免名称冲突,您可以使用普通代码中不应该使用的特殊名称,例如结尾的_
。
有了这个宏,这个:
a = SQR(b++);
将等同于此:
a = SQR(b);
b++;
警告:它可以作为扩展程序(例如GCC)在某些编译器上使用,但它不是标准的C。
如果要使用标准C,另一个选择是使用内联函数。如果您只希望它只适用于一种类型(在C11中有_Generic
,但我从未使用过,所以不知道),就可以了。