考虑
int a =10;
c = a/a; //c becomes 1.
c= a* + a/a ; //c becomes 1.
c= 5+ a* + a/a ; //c becomes 15.
c = ++a + a++ - --a - a-- + a * + a/a ; //c becomes 10.
有人可以告诉我以上是如何工作的吗?尤其是 a* 部分。第一个仅供参考。
让我们看看第三行。
c = a * + a / a;
没有后缀*
运算符 ( EXPR*
),但有一个中缀*
运算符 ( EXPR * EXPR
):乘法运算符。因此*
必须是乘法运算符。
有一个前缀+
运算符 ( +EXPR
):一元加运算符。因此,+
必须是一元加运算符。
以上等价于
c = (a * (+a)) / a;
(10 * (+a)) / a
(10 * (+10)) / a
(10 * 10) / a
100 / a
100 / 10
10
EXPR * + EXPR
下一行的情况完全相同。
c = 5 + a * + a / a
相当于
c = 5 + ((a * (+a)) / a)
5 + ((10 * (+a)) / a)
5 + ((10 * (+10)) / a)
5 + ((10 * 10) / a)
5 + (100 / a)
5 + (100 / 10)
5 + 10
15
EXPR * + EXPR
最后一行中的情况完全相同。
c = ++a + a++ - --a - a-- + a * + a/a;
相当于
c = ((((++a) + (a++)) - (--a)) - (a--)) + ((a * (+a)) / a);
最后一行a
在同一个表达式中使用和修改。在大多数语言中,此类代码的行为是未定义的,因为操作数的评估顺序是未定义的。即便如此,了解何时将引用放在堆栈上而不是副本是至关重要的,这会导致代码质量不佳。
在 Java 中,顺序是定义的,但在我的测试中实际上并非如此。让我们看一下for((++a) + (a++)) - (--a)
的初始值。10
a
使用从左到右的评估:
((++a) + (a++)) - (--a) [a=10]
(11 + (a++)) - (--a) [a=11]
(11 + 11) - (--a) [a=12]
22 - (--a) [a=12]
22 - 11 [a=11]
11
使用java
,你得到 13。因此,我实际上不会展示你的最后一行是如何评估的。这将需要检查生成的字节码,如果它甚至是有效的,这将表明它是糟糕的代码。
在这一行:
c= a* + a/a ;
是+
一元加运算符。所以它相当于
c = a * a/a;
变量a
是 10,所以10 * 10/10
是10
,不是1
。然后...
c= 5+ a* + a/a;
相当于c = 5 + a * a/a
,c
现在也是15
。然后
c = ++a + a++ - --a - a-- + a * + a/a ;
预增量更改a
为11
。后增量a++
递增到12
但产生旧值11
,22
到目前为止产生。然后 Pre decrement 递减到11
和减法产生11
。接下来,post decrement decrement to 10
but 产生旧值11
,减法产生0
。我们已经知道什么a * + a/a
是,10
。