web-dev-qa-db-ja.com

「x = x ++」の後のxとは何ですか?

これが実行されると(カーテンの後ろで)何が起こりますか?

int x = 7;
x = x++;

つまり、変数がポストインクリメントされ、1つのステートメントでそれ自体に割り当てられたときですか?これをコンパイルして実行しました。 xはまだ7ですステートメント全体の後でもです。私の本では、xが増加していると書かれています!

271
Michael

xはインクリメントされます。ただし、xの古い値を自分自身に割り当てています。


x = x++;
  1. x++xをインクリメントし、古い値を返します。
  2. x =は、古い値をそれ自体に割り当てます。

そのため、最終的にxは初期値に割り当てられます。

287
Mysticial
x = x++;

と同等です

int tmp = x;
x++;
x = tmp;
376

ステートメント:

x = x++;

以下と同等です:

tmp = x;   // ... this is capturing the value of "x++"
x = x + 1; // ... this is the effect of the increment operation in "x++" which
           //     happens after the value is captured.
x = tmp;   // ... this is the effect of assignment operation which is
           //     (unfortunately) clobbering the incremented value.

要するに、ステートメントは効果がありません。

キーポイント:

  • Postfixインクリメント/デクリメント式の値は、オペランドの値ですbeforeインクリメント/デクリメントが行われます。 (プレフィックス形式の場合、値はオペランドの値ですafter操作、)

  • 割り当て式のRHSが完全に評価されます(増分、減分、および/またはその他の副作用を含む)before値はLHSに割り当てられます。

CやC++とは異なり、Javaの式の評価順序は完全に指定されており、プラットフォーム固有のバリエーションの余地はないことに注意してください。コンパイラーは、現在のスレッドの観点からコードを実行した結果が変わらない場合にのみ、操作の順序を変更できます。この場合、コンパイラーは、それがノーオペレーションであることを証明できるため、ステートメント全体を最適化することが許可されます。


明らかでない場合:

  • 「x = x ++;」ほとんどすべてのプログラムの間違いです。
  • OP(元の質問!)は、おそらく「x ++;」を意味していました。 「x = x ++;」ではなく。
  • 同じ変数でauto inc/decrementと代入を組み合わせたステートメントは理解するのが難しく、したがっては避けるべきですそれらの正確さに関係なく。そのようなコードを書く必要はまったくありません。

FindBugsやPMDのようなコードチェッカーがこのようなコードに疑わしいフラグを立てることを願っています。

256
Stephen C
int x = 7;
x = x++;

Cで未定義の動作があります およびJavaについては この回答 を参照してください。何が起こるかはコンパイラに依存します。

33
user712092

x = x++;のような構造は、おそらく++演算子が何をするのか誤解していることを示しています。

// original code
int x = 7;
x = x++;

++演算子の削除に基づいて、同じことを行うためにこれを書き直しましょう:

// behaves the same as the original code
int x = 7;
int tmp = x; // value of tmp here is 7
x = x + 1; // x temporarily equals 8 (this is the evaluation of ++)
x = tmp; // oops! we overwrote y with 7

さて、あなたが望んでいたこと(私が思うこと)に書き換えましょう:

// original code
int x = 7;
x++;

ここでの微妙な点は、++演算子が変数xを変更することです。x + xなどの式とは異なり、 int値に評価されますが、変数x自体は変更されません。由緒あるforループのような構造を考えてみましょう。

for(int i = 0; i < 10; i++)
{
    System.out.println(i);
}

そこにi++がありますか?同じ演算子です。このforループを次のように書き換えると、同じように動作します。

for(int i = 0; i < 10; i = i + 1)
{
    System.out.println(i);
}

また、ほとんどの場合、大きな式で++演算子を使用しないことをお勧めします。 whenの微妙さのため、プリインクリメントとポストインクリメントで元の変数を変更します(それぞれ++xx++ )、追跡が困難な微妙なバグを導入するのは非常に簡単です。

16
FMM

バイトコードによる クラスファイルから取得、

どちらの割り当てもxを増やしますが、違いはwhen the value is pushed onto the stackのタイミングです

Case1では、増分の前にプッシュが発生し(その後、後で割り当てられます)(本質的に増分は何もしません)

Case2では、最初にインクリメントが行われ(8になり)、次にスタックにプッシュされます(そしてxに割り当てられます)

ケース1:

int x=7;
x=x++;

バイトコード:

0  bipush 7     //Push 7 onto  stack
2  istore_1 [x] //Pop  7 and store in x
3  iload_1  [x] //Push 7 onto stack
4  iinc 1 1 [x] //Increment x by 1 (x=8)
7  istore_1 [x] //Pop 7 and store in x
8  return       //x now has 7

ケース2:

int x=7; 
x=++x;

バイトコード

0  bipush 7     //Push 7 onto stack
2  istore_1 [x] //Pop 7 and store in x
3  iinc 1 1 [x] //Increment x by 1 (x=8)
6  iload_1  [x] //Push x onto stack
7  istore_1 [x] //Pop 8 and store in x
8  return       //x now has 8
  • ここでのスタックは、オペランドスタックを指します。ローカル:xインデックス:1タイプ:int
13
Ravi Yenugu

x = x++;」の後に増加します。 「x = ++x;」を実行すると8になります。

9
F.J

ポストインクリメント演算子は次のように機能します。

  1. オペランドの前の値を保存します。
  2. オペランドの値を増やします。
  3. オペランドの前の値を返します。

だから声明

int x = 7;
x = x++; 

次のように評価されます。

  1. xは値7で初期化されます
  2. インクリメント後演算子は、xの前の値、つまり返す7を保存します.
  3. Xをインクリメントしますつまりxは8になります
  4. Xの以前の値、つまり7を返し、xに割り当てられるため、xは再び7になります。

したがって、xは実際に増加しますが、x ++は結果をxに代入するため、xの値は以前の値にオーバーライドされます。

7
GauravLuthra

インクリメントはxが呼び出された後に行われるため、xは7に等しくなります。xが呼び出されると、++ xは8になります。

7
JonPM

xの値を再割り当てしても、まだ7です。x = ++xを試してください。

x++; // don't re-assign, just increment
System.out.println(x); // prints 8
7
Vishal

x ++は値を変数に割り当てた後にインクリメントするためです。など、この行の実行中:

x++;

varialbe xは元の値(7)のままですが、次のようにxを別の行で再度使用します

System.out.println(x + "");

8。

割り当てステートメントでxの増分値を使用する場合は、使用します

++x;

これにより、xが1ずつ増加し、その値が変数xに割り当てられます。

[編集] x = x ++ではなく、単なるx ++です。前者はxの元の値をそれ自体に割り当てるため、実際にはその行では何もしません。

6
josephus

int x = 7; x = x++;はどうなりますか?

ans-> x++は、最初にxの値を式に使用してから1増やすことを意味します。
これはあなたのケースで起こることです。 RHSのxの値はLHSの変数xにコピーされ、xの値が1増加します。

同様に、++x->が最初にxの値を1つ増やし、次にexpressionで使用することを意味します。
だからあなたの場合、x = ++x ; // where x = 7
8の値を取得します。

より明確にするために、次のコードを実行するprintfステートメントの数を調べてください。

while(i++ <5)   
  printf("%d" , ++i);   // This might clear your concept upto  great extend
4
samprat

++xは事前増分-> xは増分before使用中
x++はポストインクリメント-> xはインクリメント使用中

int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented
3

つまり、x++x = x+1と等しくありません

なぜなら:

int x = 7; x = x++;
x is 7

int x = 7; x = x = x+1;
x is 8

そして今では少し奇妙に思えます:

int x = 7; x = x+=1;
x is 8

非常にコンパイラに依存!

1
linuxeasy