为什么这两种情况下的输出不同

时间:2019-05-12 17:45:39

标签: c

请给我完整的说明。 第一个代码段在增量运算符之前具有“函数调用”(宏调用),第二个代码段在增量运算符之后具有“函数调用”。

  1. #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

  2. #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个?

2 个答案:

答案 0 :(得分:3)

要记住的是,宏提供了预处理器令牌的简单替换。特别是,他们可能会多次评估自己的论点,并且如果没有括号的保护,他们可能会产生意想不到的重新关联。

在第一个示例中,我们有

a=square (b)++;

这扩展为:

a=b*b++;

这实际上是未定义的行为,因为bb++未排序,并且b++修改了b。在您的情况下,您看到ab的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,但我从未使用过,所以不知道),就可以了。