鉴于
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;
鉴于
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
。
表达方式
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
so1
分配给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 语言通常有点让人头疼,但这有点太过分了。作为一个学习运算符优先级和副作用的学术练习,它没关系(不是很好),但是在生产代码中这样做的任何人都可能会在代码审查中对此感到悲伤。如果没有别的,它不能很好地扫描 - 只需添加一些括号(就像我在上面所做的那样)将大大有助于提高可读性。
来自 C 标准(6.5.2.4 后缀递增和递减运算符)
2 后缀 ++ 运算符的结果是操作数的值。作为副作用,操作数对象的值会递增(即,将相应类型的值 1 添加到其中)。
3 后缀--操作符类似于后缀++操作符,只是操作数的值是递减的(即减去相应类型的值1)
因此在这个表达式语句中
z = x-- == y + 1;
可以等效地重写为
z = ( x-- ) == ( y + 1 );
后缀递减表达式x--
的值是变量x
递减前的值。即表达式的值等于6
。
表达式的值y + 1
也等于,6
因为 的值y
等于5
。
最后(C 标准,6.5.9 等式运算符)
3 ==(等于)和!=(不等于)运算符类似于关系运算符,除了它们的优先级较低。108)如果指定的关系为真,则每个运算符产生 1,如果为假,则返回 0。结果的类型为 int。对于任何一对操作数,恰好有一个关系为真
因此,当表达式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
)。