你如何评价 z = x- - == y + 1;

How do you evaluate z = x- - == y + 1;

鉴于

int w = 1;
int x = 6;
int y = 5;
int z = 0;
 
z = !z || !x && !y;
printf("%d\n", z);

z = x-- == y + 1;
printf("%d\n", z);

如果 x-- 为 5 且 y+1 为 6,有人可以解释下行如何计算为 1 吗?

z = x-- == y + 1;

表达式 x-- 在 递减之前评估为 x 的值。

所以x-- == y + 1等同于6 == 5 + 1为真,则值1赋值给z.

来自 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).

3 The postfix -- operator is analogous to the postfix ++ operator, except that the value of the operand is decremented (that is, the value 1 of the appropriate type is subtracted from it)

因此在这个表达式语句中

z = x-- == y + 1;

可以等效地重写为

z = ( x-- ) == ( y + 1 );

后缀自减表达式x--的值为变量x自减前的值。即表达式的值等于6.

表达式 y + 1 的值也等于 6 因为 y 的值等于 5.

最后(C 标准,6.5.9 相等运算符)

3 The == (equal to) and != (not equal to) operators are analogous to the relational operators except for their lower precedence.108) Each of the operators yields 1 if the specified relation is true and 0 if it is false. The result has type int. For any pair of operands, exactly one of the relations is true

因此,由于表达式 x-- 的值等于表达式 y + 1 的值,因此变量 z 获得值 1.

按照以下方式保持后缀递减运算符,您可以获得预期的结果

z = ( x--, x == y + 1 );

通过插入逗号运算符。在这种情况下,在逗号运算符之后有一个序列点,这意味着在逗号运算符的第二个操作数中 x == y + 1 x 已经等于 5.

另一方面,如果你要写这样的表达式

z = --x == y + 1;

其中使用了一元递减运算符而不是后缀递减运算符 -- 那么表达式 --x 的值将等于 5(一元递减运算符的值是递减后的操作数)。在这种情况下,变量 z 获得值 0,因为 5 不等于 6(表达式 y + 1 的值)。

表达式

z = x-- == y + 1

将被解析为

z = ((x--) == (y + 1))

IOW,您正在将 x-- 结果 y + 1 结果 进行比较,并分配与 z.

的比较结果

x--的结果是x的当前值;副作用是 x 递减。所以,给定

x == 6
y == 5

然后

x--            == 6
y + 1          == 6
(x-- == y + 1) == 1

所以1赋值给z;经过这次评估,x 将等于 5.

请注意,在这种情况下,C 不会强制从左到右求值 - y + 1 可能会在 x-- 之前求值。还要注意 -- 运算符对 x 的副作用不必在评估后立即应用 - 整个事情可以评估为

t1 <- y + 1
t2 <- x
 z <- t2 == t1
 x <- x - 1

t1 <- x
t2 <- y + 1
 x <- x - 1
 z <- t1 == t2

或任何其他命令。 x 的更新和 z 的赋值可以以任何顺序发生,甚至可以同时发生(交错或并行)。

虽然惯用的 C 常常有点让人头疼,但这有点过头了。作为学习运算符优先级和副作用的学术练习,它还可以(不是很好),但是在生产代码中这样做的任何人都可能会在代码审查中遇到一些麻烦。如果不出意外,它不能很好地扫描 - 只需添加一些括号(就像我上面所做的那样)将极大地帮助提高可读性。