宏替换赋值

Macro Substitution assignment

#define MAX(x,y)(x)>(y)?(x):(y)
main()
{
    int i=10,j=5,k=0;
    k==MAX(i++,++j);
    printf("%d %d %d",i,j,k);//11 7 0
}

为什么输出是 11 7 0 而不是 11 6 0?

用实数表达式扩展宏:

k == (i++) > (++j) ? (i++) : (++j);
expr1 ? expr2 : expr3;

这是一个典型的条件表达式。

  • expr1k == (i++) > (++j)。这里其实包含了两个逻辑操作。因为 == 的优先级低于 >,所以首先评估此逻辑 (i++) > (++j),并且 ++j 在第一次逻辑测试之前完成。 j 现在是 6,我们有 10 > 6 是真的 (1)。现在来看第二个逻辑 k == 1,它的计算结果为假 (0)。
  • 因为 expr1 是假的,所以 expr3 被评估,即 (++j) 并且 ++ post-fix 意味着 j 在评估之前递增. j 现在变成 7.

预处理器将宏替换为三元运算符:

k == (x) > (y) ? (x) : (y)

比较:(x)>(y) 将首先完成并产生 1,但随后不会评估三元运算符的其余部分,因为运算符 == 具有优先权。代码相当于:

( k == ( (x) > (y) ) ) ? (x) : (y)

我们必须将该结果(为 1)与 k 进行比较:k==(x)>(y),这将产生结果 0。然后将仅评估三元运算符的第三个运算符:(y) .

总而言之,i会被评估一次,j会被评估两次。所以最终结果是 i 为 11,j 为 7。 (变量 k 将保持为 0,因为它从未被赋值。)

语句扩展为

k==(i++)>(++j)?(i++):(++j)

让我们 re-write 添加一些括号来强调在考虑优先规则时如何解析表达式:

( k == ( (i++) > (++j) ) ) ? (i++) : (++j)

请注意 > 的优先级高于 ==

现在,首先评估 (i++) > (++j),它评估为 1,并且 ij 都会递增。然后将 k1 进行比较,得出 0。因此,条件运算符的计算结果为 (++j),因此 j 又增加了一次。

总共i递增一次,j递增两次,k没有修改。因此输出如您所描述。

这是使用宏的危险的一个很好的例子。一个函数,正是你所需要的。

其他几点:

  1. 您的 main 声明不正确。应该是 int main(void).
  2. 如果您在启用警告的情况下进行编译,编译器将标记有问题的行。我的编译器说:
C:\Users\blah\Desktop>gcc main.c -Wall -o main.exe
main.c: In function 'main':
main.c:2:20: warning: suggest parentheses around comparison in operand of '==' [-Wparentheses]
 #define MAX(x,y)(x)>(y)?(x):(y)
                    ^
main.c:6:8: note: in expansion of macro 'MAX'
     k==MAX(i++,++j);
        ^

宏是您在定义它们时需要小心的地方,它们不一定会按照您期望的方式扩展。 C 中的宏的一个关键特性是它们逐字逐句地执行替换。

这个概念在K&R的书上都有很好的解释,网上也有很多教程,就google吧。