XOR 演算子を使用して、3 番目の変数を使用せずに 2 つの数値を交換するコードを見つけました^
。
コード:
int i = 25;
int j = 36;
j ^= i;
i ^= j;
j ^= i;
Console.WriteLine("i:" + i + " j:" + j);
//numbers Swapped correctly
//Output: i:36 j:25
ここで、上記のコードを同等のコードに変更しました。
私のコード:
int i = 25;
int j = 36;
j ^= i ^= j ^= i; // I have changed to this equivalent (???).
Console.WriteLine("i:" + i + " j:" + j);
//Not Swapped correctly
//Output: i:36 j:0
さて、私が知りたいのは、コードの出力が間違っているのはなぜですか?
ベストアンサー1
編集: 分かりました。
まず最初に指摘しておきたいのは、このコードは使用すべきではないということです。ただし、これを展開すると、次のコードと同等になります。
j = j ^ (i = i ^ (j = j ^ i));
( のようなより複雑な式を使用している場合はfoo.bar++ ^= i
、 が 1 回だけ評価されることが重要になります++
が、ここではより単純であると考えています。)
さて、オペランドの評価順序は常に左から右なので、まず次のようになります。
j = 36 ^ (i = i ^ (j = j ^ i));
これ(上記)が最も重要なステップです。最後に実行される XOR 演算の LHS は 36 になります。LHS は「j
RHS が評価された後の値」ではありません。
^ の RHS の評価には「1 レベルのネスト」式が含まれるため、次のようになります。
j = 36 ^ (i = 25 ^ (j = j ^ i));
次に、ネストの最も深いレベルを見ると、i
と の両方を置き換えることができますj
。
j = 36 ^ (i = 25 ^ (j = 25 ^ 36));
...これは
j = 36 ^ (i = 25 ^ (j = 61));
j
最初に RHS への代入が行われますが、結果はいずれにせよ最後に上書きされるため、これを無視できます。j
最後の代入の前に の評価はこれ以上行われません。
j = 36 ^ (i = 25 ^ 61);
これは次のものと同等になります:
i = 25 ^ 61;
j = 36 ^ (i = 25 ^ 61);
または:
i = 36;
j = 36 ^ 36;
それは次のようになります:
i = 36;
j = 0;
私考えるすべて正しく、正しい答えにたどり着きます... 評価順序に関する詳細の一部が少しずれている場合は、Eric Lippert に謝罪します :(