具有增量的三元运算符中的评估顺序

Evaluation order in ternary operator with increments

#define MAX(a,b) ((a)>(b) ? (a) : (b))
   int main(void) {
   int a=2;
   int b=3;

   int c = MAX(a++,b++); // c=((a++)>(b++) ? (a++) : (b++));
   printf("\na= %d", a);// a=3
   printf("\nb= %d", b);//b=5
   printf("\nc= %d", c);//c=4

   a=3;
   b=2;
   cc = MAX(a++,b++); // c=((a++)>(b++) ? (a++) : (b++));

   printf("\na= %d", a); // a=5
   printf("\nb= %d", b); //b=3
   printf("\nc= %d", c); //c=4

return 0;
}

我想知道为什么 c 没有评估为 5。

在我看来评估顺序应该是:

  1. 首先 a 和 be 在 (a++)>(b++)
  2. 中递增
  3. 如果例如第一个更大,则三元运算符在 c=((a++)>(b++) ? (a++) : (b++)),转到 (a++),所以 a 再次递增。
  4. 三元表达式的结果,它是两倍递增, 应分配给 c,则 c 应具有较大的值 两次递增,即 5。但是,我得到 4。我怀疑 更大的价值的第二个增量发生在最后,但我不能 解释原因,因为括号似乎表明 作业在最后。

有什么想法吗?

让我们考虑这个声明的例子

int c = MAX(a++,b++);

宏替换后会有

int c = (( a++) >( b++ ) ? (a++) : (b++));

变量ab被初始化为

int a=2;
int b=3;

由于 a 小于 b,因此第三个表达式 (b++) 将被计算为条件运算符的结果。在第一个表达式中,( a++) >( b++ ) ab 递增。在第一个表达式求值之后有一个序列点。

因此a将被设置为3b将被设置为4

如前所述,条件运算符的值是第三个表达式 (b++) 的值,其中使用了 post 增量。 post-increment 运算符的值是其操作数在递增之前的值。

来自 C 标准(6.5.2.4 后缀递增和递减运算符)

2 The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it).

所以条件运算符的值为4。该值将分配给变量 c。但作为副作用,b 的值将增加。

因此在此声明之后 a 将等于 3b 将等于 5 并且 c 将等于 4.

为清楚起见,本声明

int c = (( a++) >( b++ ) ? (a++) : (b++));

实际上可以用逻辑上等价的方式改写。

int result = a > b;
++a;
++b;

int c;

if ( result != 0 )
{
    c = a++;
}
else
{
    c = b++;
}

后缀 ++ 运算符有一个 结果 和一个 副作用 a++result是自增前a的值-给定

int a = 1;
int x = a++;

x 的值将是 1a 的值将是 2。请注意将 1 添加到 [=14= 的副作用] 不必在评估后立即应用 - 它只需要在下一个序列点之前应用。

所以,看看

((a++) > (b++)) ? (a++) : (b++)

?: 运算符强制从左到右求值,因此首先发生的是 (a++) > (b++) 被求值 1。因为 a 最初是 2b 最初是 3,所以表达式的结果是假的 (0)。 ? 运算符引入了一个序列点,因此应用 ab 的副作用 并且 a 现在是 3b 现在是 4.

由于条件表达式的结果是0,我们计算b++。同样,表达式的 结果 b (4) 的当前值,并且该值被分配给 cb 的副作用在某个时候应用,当一切都完成时,a3b5c4


  1. 虽然在该表达式中 a++b++ 可能首先被评估,因为 > 运算符不强制从左到右评估。

对于 a++ 等同于说

int temp = a;
a = a + 1;
return temp;

所以在 a=2,b=3 的情况下,我们可以转到条件 (a++)>(b++) 并且我们可以重写为

int temp1 = a;
a = a + 1;
return temp1;

和b重写为

int temp2 = b;
b = b + 1;
return temp2;

现在因为它只是一个条件语句,我们实际上只是在增量之前评估 a 和 b 的旧值,即 temp1 = 2 和 temp2 = 3 同时 a 和 b 值改变了 a = 3, b = 4。由于 temp1 < temp2 从旧值开始,我们转到三元运算符 (b++) 的 false 子句并执行与之前相同的操作

int temp3 = b;
b = b + 1;
return temp3;

所以现在 b 是 5,而返回的 temp3 是 b 以前的值,即 4。希望这对您有所帮助!