-1

考虑

    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* 部分。第一个仅供参考。

4

2 回答 2

1

让我们看看第三行。

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)的初始值。10a

使用从左到右的评估:

((++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。因此,我实际上不会展示你的最后一行是如何评估的。这将需要检查生成的字节码,如果它甚至是有效的,这将表明它是糟糕的代码。

于 2014-01-09T18:00:00.273 回答
1

在这一行:

c= a* + a/a ;

+元加运算符。所以它相当于

c = a * a/a;

变量a是 10,所以10 * 10/1010,不是1。然后...

c= 5+ a* + a/a;

相当于c = 5 + a * a/ac现在也是15。然后

c = ++a + a++ - --a - a-- + a * + a/a ;

预增量更改a11。后增量a++递增到12但产生旧值1122到目前为止产生。然后 Pre decrement 递减到11和减法产生11。接下来,post decrement decrement to 10but 产生旧值11,减法产生0。我们已经知道什么a * + a/a是,10

于 2014-01-09T17:55:11.753 回答