Apa itu x setelah “x = x ++”?

285

Apa yang terjadi (di balik tirai) ketika ini dilakukan?

int x = 7;
x = x++;

Yaitu, ketika suatu variabel ditambahkan dan ditempatkan untuk dirinya sendiri dalam satu pernyataan? Saya menyusun dan menjalankan ini. xmasih 7 bahkan setelah seluruh pernyataan . Dalam buku saya, katanya xbertambah!

Michael
sumber
9
Coba ini int x = 7; x = ++x;:, tentu saja masih kode yang mengerikan, Anda tidak perlu ditugaskan kembali. int x = 7; x++;cukup.
stivlo
7
Ini adalah praktik yang sangat buruk, jangan tambahkan variabel di baris yang sama dengan yang Anda gunakan.
Yousf
5
Saya lebih suka menggunakan x += 1, kecuali mungkin dalam loop. for(int x=0; x<7; x++)
Svish
2
@andyortlieb tidak ada objek, hanya nilai dasar.
fortran

Jawaban:

301

xtidak bertambah. Tetapi Anda menugaskan nilai lama xkembali ke dalam dirinya sendiri.


x = x++;
  1. x++menambah xdan mengembalikan nilai lamanya.
  2. x = menetapkan nilai lama kembali ke dirinya sendiri.

Jadi pada akhirnya, xakan ditugaskan kembali ke nilai awal.

Mistikal
sumber
3
Lalu, apa yang akan Anda katakan tentang x = ++ x;
Hisham Muneer
3
@HishamMuneer xbertambah terlebih dahulu sebelum dibaca dalam kasus itu, jadi Anda berakhir dengan x + 1.
@HishamMuneer Sudah terlambat. Tapi saya meletakkannya di sini karena mungkin bermanfaat untuk beberapa orang lain yang akan mencari di masa depan. Cara terbaik untuk memahami masalah ini adalah dengan melihat kode rakitan yang dibuat untuk x = x ++ dan x = ++ x. Silakan lihat jawaban Thinkingcap juga.
nantitv
Saya tahu ini sangat tua, tapi saya punya pertanyaan. Apakah urutan operasi di atas dijamin oleh standar? Mungkinkah penugasan dilaksanakan sebelum kenaikan?
Emerald Weapon
@EmeraldWeapon Ini didefinisikan di Jawa. Hanya di C / C ++ Anda melihat shenanigans semacam itu.
Mysticial
385
x = x++;

setara dengan

int tmp = x;
x++;
x = tmp;
Pangeran John Wesley
sumber
46
Lol, yay untuk definisi rekursif. Anda mungkin harus melakukan x=x+1alih-alihx++
user606723
8
@ user606723: Tidak. Maksud saya seluruh pernyataan x = x++, bukan hanya kenaikan pos x++.
Pangeran John Wesley
20
Saya tidak berpikir ini semua berguna tanpa penjelasan lebih lanjut. Misalnya, itu tidak benar yang x = ++x;juga setara dengan int tmp = x; ++x; x = tmp;, jadi dengan logika apa kita dapat menyimpulkan bahwa jawaban Anda benar (yang mana)?
kvb
4
bahkan lebih jelas lagi dalam asm x=x++ =MOV x,tmp; INC x; MOV tmp,x
forker
3
@forker: Saya pikir akan lebih jelas jika Anda menggunakan instruksi perakitan yang berlaku untuk prosesor yang digunakan Michael;)
Carl
258

Pernyataan:

x = x++;

setara dengan:

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.

Singkatnya, pernyataan itu tidak berpengaruh.

Poin-poin penting:

  • Nilai dari ekspresi kenaikan / penurunan Postfix adalah nilai operan sebelum kenaikan / penurunan terjadi. (Dalam hal bentuk Awalan, nilainya adalah nilai operan setelah operasi,)

  • RHS ekspresi penugasan sepenuhnya dievaluasi (termasuk kenaikan, penurunan, dan / atau efek samping lainnya) sebelum nilai ditugaskan ke LHS.

Perhatikan bahwa tidak seperti C dan C ++, urutan evaluasi ekspresi di Jawa benar-benar ditentukan dan tidak ada ruang untuk variasi platform-spesifik. Compiler hanya diperbolehkan untuk menyusun ulang operasi jika ini tidak mengubah hasil dari mengeksekusi kode dari perspektif utas saat ini. Dalam hal ini, kompiler akan diizinkan untuk mengoptimalkan seluruh pernyataan karena dapat dibuktikan bahwa itu adalah no-op.


Dalam hal ini belum jelas:

  • "x = x ++;" hampir pasti merupakan kesalahan dalam program apa pun.
  • OP (untuk pertanyaan awal!) Mungkin berarti "x ++;" daripada "x = x ++;".
  • Pernyataan yang menggabungkan penambahan / penetapan otomatis dan penugasan pada variabel yang sama sulit untuk dipahami, dan karenanya harus dihindari terlepas dari kebenarannya . Tidak perlu menulis kode seperti itu.

Semoga, pemeriksa kode seperti FindBugs dan PMD akan menandai kode seperti ini sebagai mencurigakan.

Stephen C
sumber
7
Sebagai catatan, OP, Anda mungkin bermaksud mengatakannya x++saja x = x++.
Jon Newmuis
3
Benar, tetapi mungkin menekankan bahwa peningkatan terjadi setelah evaluasi ekspresi tangan kanan, tetapi sebelum penugasan ke sisi kiri, maka "timpa" yang jelas
Bohemian
2
yang sepertinya salah satu twister pemrograman sekolah tinggi ... bagus untuk menjernihkan dasar-dasar Anda!
kumarharsh
1
@Alberto - Senang mendengar bahwa Anda tidak mengambil pernyataan "ahli" sebagai "kebenaran Injil". Namun, cara yang lebih baik untuk memvalidasi apa yang saya katakan adalah berkonsultasi dengan JLS. Tes kompilasi / dekompilasi Anda hanya menunjukkan bahwa apa yang saya katakan valid untuk satu kompiler Java. Orang lain dapat (secara hipotesis) berperilaku berbeda ... kecuali bahwa JLS tidak mengizinkan itu.
Stephen C
4
Hanya FYI: ini awalnya diposting ke pertanyaan yang berbeda, yang ditutup sebagai duplikat dari pertanyaan ini dan sekarang telah digabungkan.
Shog9
33
int x = 7;
x = x++;

Ini memiliki perilaku yang tidak terdefinisi dalam C dan untuk Java lihat jawaban ini . Tergantung pada kompiler apa yang terjadi.

pengguna712092
sumber
4
Tidak itu tidak tergantung pada kompiler sesuai dengan jawaban yang Anda kutip - harap edit - -1 untuk saat ini
Mr_and_Mrs_D
@ Mr_and_Mrs_D Lalu tergantung pada apa?
Mac
2
Tidak dapat ditentukan behavior_only untuk C_. Meski begitu mengatakan itu tergantung pada kompiler menyesatkan - itu menyiratkan kompiler harus menentukan jenis perilaku ini. Saya mengembalikan suara saya tetapi mempertimbangkan untuk mengedit jawaban Anda - edit: oops Saya tidak bisa - Anda harus mengeditnya terlebih dahulu: D
Mr_and_Mrs_D
16

Konstruk seperti x = x++;menunjukkan Anda mungkin salah memahami apa yang dilakukan ++operator:

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

Mari kita menulis ulang ini untuk melakukan hal yang sama, berdasarkan menghapus ++operator:

// 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

Sekarang, mari kita menulis ulang untuk melakukan (apa yang saya pikirkan) yang Anda inginkan:

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

Kehalusan di sini adalah ++operator memodifikasi variabelx , tidak seperti ekspresi seperti x + x, yang akan mengevaluasi ke nilai int tetapi membiarkan variabel xitu sendiri tidak berubah. Pertimbangkan konstruksi seperti forloop terhormat :

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

Perhatikan i++ di sana? Ini operator yang sama. Kita dapat menulis ulang forloop ini seperti ini dan akan berperilaku sama:

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

Saya juga merekomendasikan untuk tidak menggunakan ++operator dalam ekspresi yang lebih besar dalam banyak kasus. Karena kehalusan kapan memodifikasi variabel asli sebelum dan sesudah kenaikan ( ++xdan x++masing-masing), sangat mudah untuk memperkenalkan bug halus yang sulit dilacak.

FMM
sumber
13

Menurut kode Byte diperoleh dari file kelas,

Kedua tugas bertambah x, tetapi perbedaannya adalah waktu when the value is pushed onto the stack

Di Case1 , Push terjadi (dan kemudian ditetapkan) sebelum kenaikan (pada dasarnya berarti kenaikan Anda tidak menghasilkan apa-apa)

Di Case2 , Peningkatan terjadi pertama kali (membuatnya 8) dan kemudian mendorong ke tumpukan (dan kemudian ditugaskan ke x)

Kasus 1:

int x=7;
x=x++;

Kode Byte:

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

Kasus 2:

int x=7; 
x=++x;

Kode Byte

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
  • Stack di sini mengacu pada Operand Stack, lokal: x index: 1 type: int
bahkan kesalahan
sumber
Tolong jelaskan jawaban Anda.
Nihar
Mohon lihat tautan yang direferensikan dan komentar
evenprime
8

Ini bertambah setelah " x = x++;". Akan menjadi 8 jika Anda melakukannya " x = ++x;".

FJ
sumber
4
Jika bertambah setelahnya x = x++, maka seharusnya 8.
R. Martinho Fernandes
8

Operator Post Increment bekerja sebagai berikut:

  1. Menyimpan nilai operan sebelumnya.
  2. Menambah nilai operan.
  3. Kembalikan nilai operan sebelumnya.

Demikian pernyataannya

int x = 7;
x = x++; 

akan dievaluasi sebagai berikut:

  1. x diinisialisasi dengan nilai 7
  2. operator post increment menyimpan nilai x sebelumnya yaitu 7 untuk kembali.
  3. Menambahkan x, jadi sekarang x adalah 8
  4. Mengembalikan nilai x sebelumnya yaitu 7 dan ditugaskan kembali ke x, jadi x lagi menjadi 7

Jadi x memang meningkat tetapi karena x ++ menetapkan hasil kembali ke x sehingga nilai x ditimpa ke nilai sebelumnya.

GauravLuthra
sumber
Tetapi dalam msvc x adalah 8. Ya di gcc dan dentang x adalah 7.
Summer Sun
7

Peningkatan terjadi setelah x dipanggil, jadi x masih sama dengan 7. ++ x akan sama dengan 8 ketika x dipanggil

JonPM
sumber
7

Ketika Anda menetapkan ulang nilai untuk xitu masih 7. Coba x = ++xdan Anda akan mendapatkan 8 yang lain lakukan

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

karena x ++ menambah nilai SETELAH menugaskannya ke variabel. seterusnya dan selama eksekusi baris ini:

x++;

varialbe x masih akan memiliki nilai asli (7), tetapi menggunakan x lagi di baris lain, seperti

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

akan memberi Anda 8.

jika Anda ingin menggunakan nilai x yang ditambahkan pada pernyataan tugas Anda, gunakan

++x;

Ini akan bertambah x oleh 1, MAKA menetapkan nilai itu ke variabel x.

[Sunting] alih-alih x = x ++, itu hanya x ++; yang pertama memberikan nilai asli x pada dirinya sendiri, jadi sebenarnya tidak melakukan apa pun pada baris itu.

Yosephus
sumber
Yang mengatakan bertambah setelah ditetapkan, dan yang mengatakan akan mencetak 8. Bertambah sebelum ditugaskan, dan mencetak 7.
R. Martinho Fernandes
jika x awalnya 7, System.out.println (String.valueOf (x ++)); print 7. Anda yakin kita sedang berbicara tentang bahasa pemrograman yang sama?
josephus
Ya, benar. Ini ideone.com/kj2UU tidak mencetak 8, seperti ini klaim jawabannya.
R. Martinho Fernandes
ya saya salah. x = x ++ akan menetapkan 7 hingga x terlebih dahulu sebelum menambahkan x. sebagai x ++ (yang merupakan tugas itu sendiri) diselesaikan terlebih dahulu sebelum x = (apa pun), nilai yang ditugaskan ke x dalam x = (apa pun) akan mengikuti. maaf saya tidak melihat itu.
josephus
1
Sebenarnya, kenaikan adalah hal pertama yang terjadi. ideone.com/xOIDU
R. Martinho Fernandes
4

Apa yang terjadi ketika int x = 7; x = x++; ?

ans -> x++berarti nilai pakai pertama x untuk ekspresi dan kemudian meningkatkannya dengan 1.
Inilah yang terjadi dalam kasus Anda. Nilai x pada RHS disalin ke variabel x pada LHS dan kemudian nilai xmeningkat sebesar 1.

Demikian pula ++x berarti ->meningkatkan nilai x pertama dengan satu dan kemudian gunakan dalam ekspresi.
Jadi dalam kasus Anda jika Anda melakukannya, x = ++x ; // where x = 7
Anda akan mendapatkan nilai 8.

Untuk kejelasan lebih lanjut cobalah untuk mencari tahu berapa banyak pernyataan printf akan menjalankan kode berikut

while(i++ <5)   
  printf("%d" , ++i);   // This might clear your concept upto  great extend
samprat
sumber
tidak benar "Nilai x pada RHS disalin ke variabel x pada LHS dan kemudian nilai x meningkat sebesar 1" - ini akan membuat xmenjadi 8, tetapi itu adalah 7 - kenaikan terjadi antara membaca dan penugasan
user85421
3

++xadalah pra-kenaikan ->x ditambahkan sebelum digunakan
x++adalah pasca-kenaikan ->x bertambah setelah digunakan

int x = 7; -> x get 7 value <br>
x = x++; -> x get x value AND only then x is incremented
Roberto Martelloni
sumber
1

Jadi ini berarti: x++tidak sama denganx = x+1

karena:

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

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

dan sekarang sepertinya agak aneh:

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

sangat bergantung pada kompiler!

sangat mudah
sumber
2
siapa bilang itu sama di tempat pertama?
fortran
1
Jika saya jadi Anda, saya akan segera menghapus buku-buku ini xD. Bagaimanapun, itu akan seperti (x = x + 1, x-1)di C, di mana ekspresi yang dipisahkan koma diperbolehkan.
fortran
3
@fortran: Ya, dalam salinan "The Java Programming Language, Edisi Ketiga" yang sudah berumur satu dekade "di halaman 159 dikatakan" "Ekspresi i ++ sama dengan i = i +1 kecuali bahwa saya hanya dievaluasi sekali". itu di tempat pertama? James Gosling, akan muncul. Bagian dari edisi Java spec ini sangat kabur dan tidak ditentukan dengan baik, saya berasumsi bahwa edisi selanjutnya membersihkan bahasa untuk mengekspresikan semantik operator sebenarnya dengan lebih jelas.
Eric Lippert
2
@fortran: oleh "kecuali saya dievaluasi hanya sekali" standar berusaha untuk menyampaikan bahwa ekspresi seperti "M (). x ++" hanya memanggil M () sekali. Kata-kata yang kurang jelas dan lebih akurat akan menekankan bahwa ada perbedaan antara mengevaluasi saya sebagai variabel untuk menentukan lokasi penyimpanannya - yang dimaksud dengan "dievaluasi hanya sekali" di sini - dan membaca atau menulis ke lokasi penyimpanan itu - - salah satunya bisa menjadi interpretasi yang masuk akal tetapi tidak benar dari 'dievaluasi'. Jelas lokasi penyimpanan harus dibaca dan ditulis!
Eric Lippert
1
"sangat bergantung pada kompiler" - Tidak semuanya!
Stephen C
-1

x = x ++;

Ini adalah operator pasca kenaikan. Ini harus dipahami sebagai "Gunakan nilai operan dan kemudian tambahkan operan".

Jika Anda ingin kebalikannya terjadi yaitu "Menambah operan dan kemudian menggunakan nilai operan", Anda harus menggunakan operator pra-kenaikan seperti yang ditunjukkan di bawah ini.

x = ++ x;

Operator ini pertama-tama menambahkan nilai x dengan 1 dan kemudian memberikan nilai kembali ke x.

deepak
sumber
-1

Saya pikir kontroversi ini dapat diatasi tanpa masuk ke kode & hanya berpikir.

Anggap i ++ & ++ i sebagai fungsi, katakan Func1 & Func2.

Sekarang saya = 7;
Func1 (i ++) mengembalikan 7, Func2 (++ i) mengembalikan 8 (semua orang tahu ini). Secara internal kedua fungsi menambah i hingga 8, tetapi keduanya mengembalikan nilai yang berbeda.

Jadi i = i ++ memanggil fungsi Func1. Di dalam fungsi saya naik ke 8, tetapi setelah selesai fungsi mengembalikan 7.

Jadi akhirnya 7 dialokasikan untuk saya. (Jadi pada akhirnya, saya = 7)

Pranav Mahajan
sumber
2
Tidak ada "kontroversi" yang valid di sini. Kode tersebut menunjukkan perilaku dengan cara tertentu, dan perilaku tersebut sesuai dengan JLS. Siapa pun yang berpikir itu berperilaku berbeda juga belum mencobanya, atau mereka diperdaya. (Ini agak seperti mengatakan bahwa 7 x 7 adalah 49 adalah "kontroversial" ketika seseorang lupa tabel waktu mereka ...)
Stephen C
-2

Ini karena Anda menggunakan operator pasca kenaikan. Pada baris kode berikut

x = x++;

Yang terjadi adalah, Anda menetapkan nilai x ke x. x ++ kenaikan x setelah nilai x ditugaskan ke x. Begitulah cara operator pasca kenaikan bekerja. Mereka bekerja setelah sebuah pernyataan dieksekusi. Jadi dalam kode Anda, x dikembalikan terlebih dahulu setelah itu kemudian meningkat.

Jika Anda melakukannya

x = ++x;

Jawabannya adalah 8 karena Anda menggunakan operator pra-kenaikan. Ini menambah nilai terlebih dahulu sebelum mengembalikan nilai x.

Segera
sumber