这个表达式在 C 中的计算结果是真还是假(1 或 0)?

use*_*550 3 c conditional-operator unary-operator sequence-points postfix-operator

#include<stdio.h>
int main()
{
    int a=4;
    int b=4;
    int c= a++ < ++b? 1 : 0;
    
    printf ("%d",c);
}
Run Code Online (Sandbox Code Playgroud)

已知在 处有一个序列点?,这意味着前缀和后缀操作都必须在该点完成。还知道(?)b在比较之前增加。然而,是a在比较之前还是之后增加呢?

如果在测试之前递增<,则布尔值计算结果为 false 并c设置为 0,否则为 true 并c设置为 1。在我的编译器中,它计算结果为 true,这意味着a++在比较操作之后执行并c设置为1.

但这种行为是规范的一部分吗?

我修改为

#include<stdio.h>
int main()
{
    int a=4;
    int b=4;
    int d=2;
    int c= a++ + d < ++b + d? 1 : 0;
    
    printf ("%d",c);
}
Run Code Online (Sandbox Code Playgroud)

它的计算结果仍然为 1。后缀必须在 之前完成?,但这真的确保它在比较之后发生吗<

Chr*_*ris 9

a++返回增量a 之前的值。返回增量++b的值。因此,这会减少到减少到 哪一个为真,因此表达式的计算结果为。b 4 + 2 < 5 + 26 < 7a++ + d < ++b + d ? 1 : 01

由于 和ab没有在表达式中使用多次,因此不存在未定义的行为。


Ste*_*mit 6

还知道(?) b 在比较之前递增。然而,a是在比较之前还是之后递增呢?

这是一个微妙的观点,但了解这里到底发生了什么很重要。

子表达式a++和 都++b件事。它们计算要在周围表达式中使用的新值,更新正在操作的变量的存储值。

这也是如此a++

  1. 它产生 (4) 的旧值a到周围的表达式
  2. 它将新值 (5) 存储到 中a

++b这样做:

  1. b它向周围的表达式产生 (4+1 或 5) 的新值
  2. 它将新值 (5) 存储到 中b

<请注意,在这两种情况下,操作员关心的是事情 1 。而且,在这两种情况下,事情 1 都是绝对定义,它不依赖于时间。

或者,换句话说,询问“ a/是b在比较之前还是之后递增?” 这不是一个真正正确的问题。价值观ab+1参与比较,仅此而已。

时间出现的地方是事情 2。我们不确切地知道新值何时存储回a。我们也不知道新值何时存储回b. 我们所知道的是,这些存储将在下一个序列点之前的某个时间发生(正如您正确地注意到的那样,在本例中是?三元运算符的一部分)。

但一切都不取决于这些时间,因此这里没有未定义的行为。

当以下任一情况时,就会出现未定义的行为

  1. 被修改的变量(ab) 也有其值在表达式的其他地方独立使用,这意味着我们不知道该使用是使用旧值还是新值
  2. 同一个变量被修改两次,这意味着我们不知道两次修改中哪一个“获胜”

但是,同样,这些问题都没有在这里发生,因此表达式是明确定义的。