为什么复合赋值 (+=) 因语言(Java、C++)而异?
Why does compound assignment (+=) differ between languages (Java, C++)?
+=
的定义在 Java 和 C++ 中似乎是相同的,但是,它们的表现不同。
考虑以下 C++ 代码:
#include <iostream>
int n;
int f(int x) {
n += x;
return x;
}
int main() {
n = 0;
n = n + f(3);
std::cout<<n<<" ";
n = 0;
n += f(3);
std::cout<<n<<" ";
n = 0;
n = f(3) + n;
std::cout<<n<<std::endl;
}
这输出:3 6 6
Java中的类似代码输出:3 3 6
,这里是参考代码。
static int n;
public static void main(String[] args) {
n = 0;
n = n + f(3);
System.out.println(n);
n = 0;
n += f(3);
System.out.println(n);
n = 0;
n = f(3) + n;
System.out.println(n);
}
public static int f(int x) {
n += x;
return x;
}
查看 C++ and Java 的文档,他们写了类似的定义:
C++:
E1 op= E2 (where E1 is a modifiable lvalue expression and E2 is an rvalue expression or a braced-init-list (since C++11)) is exactly the same as the behavior of the expression E1 = E1 op E2, except that the expression E1 is evaluated only once and that it behaves as a single operation with respect to indeterminately-sequenced function calls
Java:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
出于好奇,我在 Python 中检查了这个,它与 Java 的输出相同。当然,这样写代码是非常糟糕的做法,但我仍然很好奇解释。
我怀疑 +=
在不同的语言中,变量的求值顺序是不同的,但我不知道具体是怎么回事。我在定义中遗漏了什么,复合赋值运算符是如何计算的?
评估顺序 - 严格 left-right in Java.
n += f(3);
所以:'n'是0。 f(3) returns 3.所以我们把0和3相加,把结果赋给n。 f() 中对 n 的赋值无效。
Java 语言规范:
[…] the value of the left-hand operand is saved and then the
right-hand operand is evaluated. […]
对于 C++,我相信(但没有检查)求值顺序是未定义的。
在你的例子中,调用了 f(3),n 变成了 3,然后 f(3) 的结果被添加到 n 的新值中。
要判断一个表达式的含义,不能只看所涉及的运算符。求值顺序很重要,在同一个表达式中修改和使用变量的地方,细则很重要(结果可能会也可能不会在语言中定义)。
这与 求值顺序 的关系比“复合赋值运算符的作用”更多,因此您会在两种语言的规范。
对于Java,JLS §15.7:
The left-hand operand of a binary operator appears to be fully
evaluated before any part of the right-hand operand is evaluated.
If the operator is a compound-assignment operator (§15.26.2), then
evaluation of the left-hand operand includes both remembering the
variable that the left-hand operand denotes and fetching and saving
that variable's value for use in the implied binary operation.
所以 +=
左边的 n
先求值,到 0
。然后右侧的计算结果为 3
。然后将此值与左侧的总和写入 n
.
对于 C++,Evaluation Order:
查看“规则”部分中的第 20 项:
In every simple assignment expression E1=E2 and every compound assignment expression E1@=E2, every value computation and side-effect of E2 is sequenced before every value computation and side effect of E1
在这里,首先评估 E2(右侧),直到 3,然后评估左侧。此时,n
已被 f
更改为 3,因此左侧的计算结果也为 3。
+=
的定义在 Java 和 C++ 中似乎是相同的,但是,它们的表现不同。
考虑以下 C++ 代码:
#include <iostream>
int n;
int f(int x) {
n += x;
return x;
}
int main() {
n = 0;
n = n + f(3);
std::cout<<n<<" ";
n = 0;
n += f(3);
std::cout<<n<<" ";
n = 0;
n = f(3) + n;
std::cout<<n<<std::endl;
}
这输出:3 6 6
Java中的类似代码输出:3 3 6
,这里是参考代码。
static int n;
public static void main(String[] args) {
n = 0;
n = n + f(3);
System.out.println(n);
n = 0;
n += f(3);
System.out.println(n);
n = 0;
n = f(3) + n;
System.out.println(n);
}
public static int f(int x) {
n += x;
return x;
}
查看 C++ and Java 的文档,他们写了类似的定义:
C++:
E1 op= E2 (where E1 is a modifiable lvalue expression and E2 is an rvalue expression or a braced-init-list (since C++11)) is exactly the same as the behavior of the expression E1 = E1 op E2, except that the expression E1 is evaluated only once and that it behaves as a single operation with respect to indeterminately-sequenced function calls
Java:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
出于好奇,我在 Python 中检查了这个,它与 Java 的输出相同。当然,这样写代码是非常糟糕的做法,但我仍然很好奇解释。
我怀疑 +=
在不同的语言中,变量的求值顺序是不同的,但我不知道具体是怎么回事。我在定义中遗漏了什么,复合赋值运算符是如何计算的?
评估顺序 - 严格 left-right in Java.
n += f(3);
所以:'n'是0。 f(3) returns 3.所以我们把0和3相加,把结果赋给n。 f() 中对 n 的赋值无效。
Java 语言规范:
[…] the value of the left-hand operand is saved and then the right-hand operand is evaluated. […]
对于 C++,我相信(但没有检查)求值顺序是未定义的。
在你的例子中,调用了 f(3),n 变成了 3,然后 f(3) 的结果被添加到 n 的新值中。
要判断一个表达式的含义,不能只看所涉及的运算符。求值顺序很重要,在同一个表达式中修改和使用变量的地方,细则很重要(结果可能会也可能不会在语言中定义)。
这与 求值顺序 的关系比“复合赋值运算符的作用”更多,因此您会在两种语言的规范。
对于Java,JLS §15.7:
The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.
If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.
所以 +=
左边的 n
先求值,到 0
。然后右侧的计算结果为 3
。然后将此值与左侧的总和写入 n
.
对于 C++,Evaluation Order:
查看“规则”部分中的第 20 项:
In every simple assignment expression E1=E2 and every compound assignment expression E1@=E2, every value computation and side-effect of E2 is sequenced before every value computation and side effect of E1
在这里,首先评估 E2(右侧),直到 3,然后评估左侧。此时,n
已被 f
更改为 3,因此左侧的计算结果也为 3。