[英]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++:
E1 op= E2(其中 E1 是一個可修改的左值表達式,E2 是一個右值表達式或花括號初始化列表 (C++11 起))與表達式 E1 = E1 op E2 的行為完全相同,除了表達式 E1 僅被評估一次,並且對於不確定順序的 function 調用,它表現為單個操作
Java:
E1 op= E2 形式的復合賦值表達式等同於 E1 = (T) ((E1) op (E2)),其中 T 是 E1 的類型,只是 E1 僅計算一次。
出於好奇,我在 Python 中查看了這個,它與 Java 具有相同的 output。當然,這樣編寫代碼是非常糟糕的做法,但我仍然很好奇,希望得到解釋。
我懷疑在不同的語言中, +=
的變量求值順序是不同的,但我不知道具體是怎樣的。 我在定義中遺漏了什么,復合賦值運算符是如何計算的?
這更多地與評估順序有關,而不是“復合賦值運算符的作用”,因此您會在兩種語言規范的“評估順序”部分找到更多有用的東西。
對於 Java, JLS §15.7 :
二元運算符的左側操作數似乎在右側操作數的任何部分被求值之前被完全求值。
如果運算符是復合賦值運算符(第 15.26.2 節),則左側操作數的計算包括記住左側操作數表示的變量以及獲取和保存該變量的值以用於隱含的二元運算.
因此+=
左側的n
首先計算為0
。 然后右側評估為3
。 然后將此值與左側的總和寫入n
。
對於 C++,評估訂單:
查看“規則”部分中的第 20 項:
在每個簡單賦值表達式 E1=E2 和每個復合賦值表達式 E1@=E2 中,E2 的每個值計算和副作用在 E1 的每個值計算和副作用之前排序
這里,首先評估 E2(右側)到 3,然后評估左側。 此時, n
已被f
更改為 3,因此左側的計算結果也為 3。
評估順序 - 嚴格按照 Java 中的左右順序。
n += f(3);
所以:'n' 是 0。f(3) 返回 3。所以我們將 0 和 3 相加,並將結果賦給 n。 f() 中對 n 的賦值無效。
Java 語言規范:
[...] 保存左側操作數的值,然后評估右側操作數。 […]
對於 C++,我相信(但沒有檢查)評估順序是未定義的。
在您的例子中,調用了 f(3),n 變為 3,然后將 f(3) 的結果添加到 n 的新值中。
要確定表達式的含義,不能只看涉及的運算符。 評估順序很重要,並且在同一表達式中修改和使用變量的地方,細則很重要(結果可能會也可能不會在語言中定義)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.