13

今日、私はEric Lippertによる、演算子の優先順位と評価の順序の間の神話を明らかにしようとしている記事に出くわしました。最後に、私を混乱させた2つのコードスニペットがありました。最初のスニペットは次のとおりです。

      int[] arr = {0};
      int value = arr[arr[0]++];

ここで、変数値の値について考えるとき、単純に1と計算します。これが私がそれが機能していると思った方法です。

  1. まず、arrを1つの項目を含むintの配列として宣言します。このアイテムの値は0です。
  2. 次に、この場合はarr[0]-0の値を取得します。
  3. 3番目にarr[ステップ2の値]の値を取得します(これはまだ0です)-arr[0]を再度取得します--まだ0です。
  4. 4番目に、ステップ3(0)の値を変数値に割り当てます。--value=0になりました
  5. ステップ2の値に追加します1---ここでarr[0]=1です。

どうやらこれは間違っています。インクリメントが実際にいつ発生するかについての明示的なステートメントをC#仕様で検索しようとしましたが、見つかりませんでした。
2番目のスニペットは、このトピックに関するEricのブログ投稿のコメントからのものです。

 int[] data = { 11, 22, 33 }; 
 int i = 1;
 data[i++] = data[i] + 5;

配列を宣言し、iに1を割り当てた後、このプログラムがどのように実行されるかを次に示します。[私と一緒にplzクマ]

  1. データを取得[i]-1
  2. ステップ1の値に値5--6を追加します
  3. data [i](まだ1)にステップ2の値を割り当てます--data [i] = 6
  4. インクリメントi--i=2

私の理解によると、この配列には値{11、27、33}が含まれているはずです。ただし、ループして配列値を出力すると、{11、38、33}が得られました。これは、配列を逆参照する前にポストインクリメントが発生したことを意味します。
どうして?この投稿の増分は投稿であると想定されていませんか?つまり、他のすべての後に起こります。
私は何が欠けているのですか?

4

6 に答える 6

20

ポストインクリメント操作は、式全体の評価の一部として発生します。これは、値が評価された後、他の式が評価される前に発生する副作用です。

つまり、任意の式 E について、E++ (正当な場合) は (疑似コード) のようなものを表します。

T tmp = E;
E += 1;
return tmp;

これはすべて、E++ の評価の一部であり、他の何かが評価される前です。

詳細については、C# 3.0 仕様のセクション 7.5.9 を参照してください。


さらに、(この場合のように) LHS が変数として分類される代入演算では、RHS が評価される前にLHS が評価されます。

あなたの例では:

int[] data = { 11, 22, 33 }; 
int i = 1;
data[i++] = data[i] + 5;

次と同等です。

int[] data = { 11, 22, 33 }; 
int i = 1;
// Work out what the LHS is going to mean...
int index = i;
i++;
// We're going to assign to data[index], i.e. data[1]. Now i=2.

// Now evaluate the RHS
int rhs = data[i] + 5; // rhs = data[2] + 5 == 38

// Now assign:
data[index] = rhs;

これに関する仕様の関連ビットは、セクション 7.16.1 (C# 3.0 仕様) です。

于 2009-08-11T13:16:45.657 に答える
5

最初のスニペットのシーケンスは次のとおりです。

  1. あなたが説明したようにarrを宣言します:
  2. 0であるarr[0]の値を取得します
  3. arr[0]の値を1にインクリメントします。
  4. arr[0]であるarr[(#2の結果)]の値を取得します。これは(#3ごとに)1です。
  5. その結果をに保存しvalueます。
  6. 値=1

2番目のスニペットの場合、評価は引き続き左から右です。

  1. 結果はどこに保存しますか?data[1]であるdata[i++]では、現在はi = 2
  2. 何を追加しますか?data [i] + 5、これはdata [2] + 5、つまり38になります。

欠けている部分は、「投稿」は「他のすべての後」を意味しないということです。「その変数の現在の値を取得した直後」という意味です。コード行の「途中」で発生するポストインクリメントは完全に正常です。

于 2009-08-11T13:27:57.983 に答える
2
data[i++] // => data[1], then i is incremented to 2

data[1] = data[2] + 5 // => 33 + 5
于 2009-08-11T13:17:34.783 に答える
0

ポストインクリメント演算子は、その値が使用された後に変数をインクリメントすることを期待します。この場合、変数は、変数への2番目の参照の前にインクリメントされます。

そうでなければ、あなたは書くことができます

data[i++] = data[i++] + data[i++] + data[i++] + 5

あなたが言うようであれば、私が報告した命令では、実際には何もしないので、インクリメント演算子を削除することができます。

于 2009-08-11T13:27:11.917 に答える
-4

一部のコンパイラが i++ を ++i に最適化することが原因である可能性があります。ほとんどの場合、最終結果は同じですが、コンパイラが間違っているというまれなケースの 1 つに思えます。

現在、これを確認するために Visual Studio にアクセスすることはできませんが、コードの最適化を無効にして、結果が同じになるかどうかを確認してください。

于 2009-08-11T13:17:46.403 に答える