问题描述
鉴于
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
before 递减。
所以 x-- == y + 1
与 6 == 5 + 1
相同,为真,则将值 1 分配给 z
。
表达式
z = x-- == y + 1
将被解析为
z = ((x--) == (y + 1))
IOW,您正在将 x--
的 result 与 y + 1
的 result 进行比较,并将该比较的结果分配给 {{ 1}}。
z
的结果是 x--
的当前值;副作用是 x
递减。所以,给定
x
然后
x == 6
y == 5
所以x-- == 6
y + 1 == 6
(x-- == y + 1) == 1
被分配给1
;在此评估之后,z
将等于 x
。
请注意,在这种情况下,C 不会强制从左到右求值 - 5
可以在 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
的分配可以以任何顺序发生,甚至可以同时发生(交错或并行)。
虽然惯用的 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) Each 如果指定的关系为真,则运算符的结果为 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
的值)。
类似的表达
z = x-- == y + 1;
在负责任的 C 编程中几乎没有位置。没有人应该写出这样的表达。任何人都不应将其编写在生产程序、测试程序或练习中供学生学习。
是的,您必须确切了解 x--
的作用。
是的,如果你成为一名专业的 C 程序员,你会遇到糟糕的代码,你必须弄清楚它的作用。
但如果你还在学习,在我看来,被要求使用这样的表达式在教学上相当于 hazing。