Untuk i = 0, mengapa (i + = i ++) sama dengan 0?

253

Ambil kode berikut (dapat digunakan sebagai Aplikasi Konsol):

static void Main(string[] args)
{
    int i = 0;
    i += i++;
    Console.WriteLine(i);
    Console.ReadLine();
}

Hasilnya iadalah 0. Saya mengharapkan 2 (seperti yang dilakukan beberapa rekan saya). Mungkin kompiler membuat semacam struktur yang menghasilkan inol.

Alasan saya mengharapkan 2 adalah bahwa, di garis pemikiran saya, pernyataan tangan kanan akan dievaluasi terlebih dahulu, menambah i dengan 1. Daripada ditambahkan ke i. Karena saya sudah 1, itu menambahkan 1 ke 1. Jadi 1 + 1 = 2. Jelas ini bukan yang terjadi.

Bisakah Anda menjelaskan apa yang dilakukan kompiler atau apa yang terjadi pada saat runtime? Mengapa hasilnya nol?

Semacam penyangkalan: Saya sangat sadar Anda tidak akan (dan mungkin tidak seharusnya) menggunakan kode ini. Saya tahu saya tidak akan pernah. Namun demikian, saya merasa menarik untuk mengetahui mengapa itu bertindak sedemikian rupa dan apa yang sebenarnya terjadi.

Peter
sumber
57
bukankah seharusnya hasil yang diharapkan adalah 1? i (0) + = i ++ (1) karena itu 0 + = 1 = 1
aleation
11
Ini berfungsi seperti yang diharapkan
Steve's D
177
Berapa banyak variasi pertanyaan ini yang akan ditanyakan?
mowwwalker
20
Preincrementation akan menambah nilai sebelum melakukan aksi i + = ++ saya akan memberikan Anda 1
Pierluc SS
21
Mengapa semua orang fokus pada postincrement sebelum vs? The "aneh" hal adalah bahwa nilai dari ipada sisi kiri dari +=yang "cache" sebelum sisi kanan dievaluasi. Ini kontra-intuitif, karena akan, misalnya, memerlukan operasi penyalinan jika isuatu objek. (Tolong jangan salah mengerti saya: Saya benar-benar setuju untuk menyatakan bahwa itu 0adalah jawaban yang benar dan sesuai standar.)
JohnB

Jawaban:

425

Ini:

int i = 0;
i += i++

Dapat dilihat seperti yang Anda lakukan (berikut ini adalah penyederhanaan berlebih):

int i = 0;
i = i + i; // i=0 because the ++ is a postfix operator and hasn't been executed
i + 1; // Note that you are discarding the calculation result

Apa yang sebenarnya terjadi adalah lebih terlibat dari itu - lihatlah pada MSDN, 7.5.9 Peningkatan dan penurunan operator postfix :

Pemrosesan run-time dari operasi kenaikan atau penurunan postfix dari bentuk x ++ atau x-- terdiri dari langkah-langkah berikut:

  • Jika x diklasifikasikan sebagai variabel:

    • x dievaluasi untuk menghasilkan variabel.
    • Nilai x disimpan.
    • Operator yang dipilih dipanggil dengan nilai x yang disimpan sebagai argumennya.
    • Nilai yang dikembalikan oleh operator disimpan di lokasi yang diberikan oleh evaluasi x.
    • Nilai x yang disimpan menjadi hasil operasi.

Perhatikan bahwa karena urutan prioritas , postfix ++terjadi sebelumnya += , tetapi hasilnya akhirnya tidak digunakan (seperti nilai sebelumnya iyang digunakan).


Dekomposisi yang lebih teliti dari i += i++bagian-bagian yang dibuatnya mengharuskan seseorang untuk mengetahui bahwa keduanya +=dan ++bukan atom (yaitu, tidak satu pun adalah operasi tunggal), bahkan jika mereka terlihat seperti itu. Cara ini diterapkan melibatkan variabel sementara, salinan isebelum operasi berlangsung - satu untuk setiap operasi. (Saya akan menggunakan nama iAdddan iAssignuntuk variabel sementara yang digunakan untuk ++dan +=masing - masing).

Jadi, perkiraan yang lebih dekat dengan apa yang terjadi adalah:

int i = 0;
int iAdd = i; // Copy of the current value of i, for ++
int iAssign = i; // Copy of the current value of i, for +=

i = i + 1; // i++ - Happens before += due to order of precedence
i = iAdd + iAssign;
Oded
sumber
3
@Oded ++Operasi ini dilakukan sebelum evaluasi pernyataan selesai. Jadi +=menimpa nilainya. Inikah yang terjadi?
Anirudh Ramanathan
6
@Oded sebenarnya yang: int i = 0; i = i + 1; (postfix) i = 0; (assignment). Jika Anda menggunakan saya di tempat lain dalam pernyataan itu, itu akan mengevaluasi ke 1 pada saat itu.
drch
@Cthulhu - Intinya. The jawaban oleh DTB masuk ke rincian.
Oded
6
Saya tidak membeli yang ini. Jawaban oleh @yoriy jauh lebih akurat. Pertama, dalam jawaban Anda, Anda mengatakan bahwa baris terakhir adalah i+1padahal seharusnya i=i+1. Bukankah itu apa i++?
recluze
3
Bagian pertama dari jawabannya adalah redundan. Contoh kode terakhir Anda bisa saja melakukannya IMHO. +1 sekalipun.
corazza
194

Pembongkaran kode yang sedang berjalan:

int i = 0;
  xor         edx, edx
  mov         dword ptr i, edx         // set i = 0
i += i++;
  mov         eax, dword ptr i         // set eax = i (=0)
  mov         dword ptr tempVar1, eax  // set tempVar1 = eax (=0)
  mov         eax, dword ptr i         // set eax = 0 ( again... why??? =\ )
  mov         dword ptr tempVar2, eax  // set tempVar2 = eax (=0)
  inc         dword ptr i              // set i = i+1 (=1)
  mov         eax, dword ptr tempVar1  // set eax = tempVar1 (=0)
  add         eax, dword ptr tempVar2  // set eax = eax+tempVar2 (=0)
  mov         dword ptr i, eax         // set i = eax (=0)

Kode Setara

Ini mengkompilasi ke kode yang sama dengan kode berikut:

int i, tempVar1, tempVar2;
i = 0;
tempVar1 = i; // created due to postfix ++ operator
tempVar2 = i; // created due to += operator
++i;
i = tempVar1 + tempVar2;

Pembongkaran kode kedua (hanya untuk membuktikan bahwa mereka sama)

int i, tempVar1, tempVar2;
i = 0;
    xor         edx, edx
    mov         dword ptr i, edx
tempVar1 = i; // created due to postfix ++ operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar1, eax
tempVar2 = i; // created due to += operator
    mov         eax, dword ptr i
    mov         dword ptr tempVar2, eax
++i;
    inc         dword ptr i
i = tempVar1 + tempVar2;
    mov         eax, dword ptr tempVar1
    add         eax, dword ptr tempVar2
    mov         dword ptr i, eax

Membuka jendela pembongkaran

Kebanyakan orang tidak tahu, atau bahkan tidak ingat, bahwa mereka dapat melihat kode perakitan di-memori akhir, menggunakan jendela Visual Studio Disassembly . Ini menunjukkan kode mesin yang sedang dieksekusi, itu bukan CIL.

Gunakan ini saat men-debug:

Debug (menu) -> Windows (submenu) -> Disassembly

Jadi apa yang terjadi dengan postfix ++?

Postfix ++ memberi tahu bahwa kami ingin menambah nilai operan setelah evaluasi ... yang semua orang tahu ... yang sedikit membingungkan adalah arti dari "setelah evaluasi" .

Jadi, apa artinya "setelah evaluasi" :

  • penggunaan lain dari operan, pada baris kode yang sama harus terpengaruh:
    • a = i++ + i yang kedua saya dipengaruhi oleh kenaikan tersebut
    • Func(i++, i) yang kedua saya terpengaruh
  • penggunaan lain pada saluran yang sama menghormati operator hubungan pendek seperti ||dan &&:
    • (false && i++ != i) || i == 0 yang ketiga saya tidak terpengaruh oleh i ++ karena tidak dievaluasi

Jadi apa arti dari: i += i++;?

Itu sama dengan i = i + i++;

Urutan evaluasi adalah:

  1. Simpan i + i (yaitu 0 + 0)
  2. Kenaikan i (i menjadi 1)
  3. Tetapkan nilai langkah 1 ke i (i menjadi 0)

Bukan berarti kenaikan itu dibuang.

Apa arti dari: i = i++ + i;?

Ini tidak sama dengan contoh sebelumnya. Yang ke-3 idipengaruhi oleh kenaikan tersebut.

Urutan evaluasi adalah:

  1. Store i (yaitu 0)
  2. Kenaikan i (i menjadi 1)
  3. Simpan nilai langkah 1 + i (yaitu 0 + 1)
  4. Tetapkan nilai langkah 3 ke i (i menjadi 1)
Miguel Angelo
sumber
22
+1 ++ - untuk diseksi hardcore belaka. Chuck Norris akan bangga :) Saya kira Anda membuat asumsi bahwa OP ada pada Intel, bukan port Mono ...
StuartLC
19
C # memiliki urutan evaluasi yang jelas untuk ekspresi, dan kode objek hanya mengimplementasikan urutan itu. Output kode mesin bukan alasan atau penjelasan untuk urutan evaluasi.
Kaz
8
Kode mesin memudahkan untuk memahami bagaimana urutan evaluasi diimplementasikan IMO.
Kevin
5
@ SattuLC Saya melihat apa yang Anda lakukan di sana. Malu tentang upvote dibuang.
Steffan Donal
2
a++ + atidak sama dengan a + a++karena ini bukan lagi matematika murni. Hukum komutatif dalam aljabar tidak memperhitungkan kemungkinan bahwa variabel mengubah nilai di tengah ekspresi. Matematika hanya memetakan dengan rapi ke pemrograman ketika pemrograman adalah pemrograman fungsional. Dan bahkan tidak, karena keterbatasan representasional. Misalnya angka floating-point terkadang berperilaku seperti real dan kadang tidak. Bahkan tanpa efek samping, hukum komutatif dan asosiatif yang berlaku untuk bilangan real dalam matematika menerobos angka floating-point.
Kaz
61
int i = 0;
i += i++;

dievaluasi sebagai berikut:

Stack<int> stack = new Stack<int>();
int i;

// int i = 0;
stack.Push(0);                   // push 0
i = stack.Pop();                 // pop 0 --> i == 0

// i += i++;
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(i);                   // push 0
stack.Push(1);                   // push 1
i = stack.Pop() + stack.Pop();   // pop 0 and 1 --> i == 1
i = stack.Pop() + stack.Pop();   // pop 0 and 0 --> i == 0

yaitu idiubah dua kali: sekali oleh i++ekspresi dan sekali oleh +=pernyataan.

Tetapi operan dari +=pernyataan itu adalah

  • nilai isebelum evaluasi i++(sisi kiri +=) dan
  • nilai isebelum evaluasi i++(sisi kanan +=).
dtb
sumber
Ah ini penjelasan yang fantastis. Mengingatkan saya pada saat saya bekerja pada kalkulator berbasis tumpukan menggunakan notasi polish terbalik.
Nathan
36

Pertama, i++pengembalian 0. Kemudian iditambahkan oleh 1. Terakhir idiatur ke nilai awal iyaitu 0 ditambah nilai yang i++dikembalikan, yang juga nol. 0 + 0 = 0.

Jong
sumber
2
Tapi itu i += i++;tidak i = i++;, jadi nilai i++(0) ditambahkan i, dan tidak " idiatur ke nilai yang i++dikembalikan". Sekarang pertanyaannya adalah, ketika menambahkan nilai yang i++dikembalikan ke i, akankah inilai bertambah atau nilai tidak bertambah? Jawabannya, temanku, tertulis dalam spesifikasi.
Daniel Fischer
Benar, saya akan memperbaikinya. Tapi bagaimanapun sejak i = 0awalnya, i += somethingsama dengan i = 0 + somethingyang i = something.
Jong
32

Ini hanya dari kiri ke kanan, evaluasi bottom-up dari pohon sintaksis abstrak. Secara konseptual, pohon ekspresi berjalan dari atas ke bawah, tetapi evaluasi terbuka ketika rekursi muncul kembali ke atas pohon dari bawah.

// source code
i += i++;

// abstract syntax tree

     +=
    /  \
   i    ++ (post)
         \
         i

Evaluasi dimulai dengan mempertimbangkan simpul akar +=. Itu adalah konstituen utama dari ekspresi. Operan kiri +=harus dievaluasi untuk menentukan tempat kami menyimpan variabel, dan untuk mendapatkan nilai sebelumnya yang nol. Selanjutnya, sisi kanan harus dievaluasi.

Sisi kanan adalah ++operator pasca kenaikan . Ini memiliki satu operan, iyang dievaluasi baik sebagai sumber nilai, dan sebagai tempat menyimpan nilai. Operator mengevaluasi i, menemukan 0, dan akibatnya menyimpan a 1ke lokasi itu. Ini mengembalikan nilai sebelumnya,, 0sesuai dengan semantik mengembalikan nilai sebelumnya.

Sekarang kontrol kembali ke +=operator. Sekarang memiliki semua info untuk menyelesaikan operasinya. Ia tahu tempat menyimpan hasil (lokasi penyimpanan i) serta nilai sebelumnya, dan memiliki nilai untuk ditambahkan ke nilai sebelumnya, yaitu 0. Jadi, iberakhir dengan nol.

Seperti Java, C # telah membersihkan aspek yang sangat tidak jelas dari bahasa C dengan memperbaiki urutan evaluasi. Kiri-ke-kanan, bawah-ke-atas: urutan paling jelas yang mungkin diharapkan oleh pembuat kode.

Kaz
sumber
+1: Saya setuju dengan Anda, kecuali setiap pembuat kode berharap bahwa ... Saya mengharapkannya sama seperti ini: SetSum(ref i, Inc(ref i))dengan int SetSum(ref int a, int b) { return a += b; }dan int Inc(ref int a) { return a++; }... tentu saja saya tidak lagi mengharapkan itu.
Miguel Angelo
Juga, apa yang saya harapkan tidak konsisten! Itu tidak akan sama Set(ref i, Sum(i, Inc(ref i)))dengan int Set(ref int a, int b) { return a = b; }dan int Sum(int a, int b) { return a + b; }.
Miguel Angelo
Terima kasih; Anda mengisyaratkan cacat / tidak lengkapnya jawaban saya yang harus saya perbaiki.
Kaz
Masalahnya SetSumadalah bahwa ia tidak mengevaluasi operan kiri i, tetapi hanya mengambil alamatnya, jadi itu tidak setara dengan evaluasi kiri dan kanan yang lengkap dari operan. Anda butuh sesuatu seperti SetSum(ref i, i, PostInc(ref i)). Argumen kedua SetSumadalah nilai yang akan ditambahkan, di mana kita hanya menggunakan iuntuk menentukan nilai sebelumnya dari i. SetSumhanya int SetSum(ref int dest, int a, int b) { return dest = a + b; }.
Kaz
Kebingungan terjadi (setidaknya bagi saya) dengan operator + =, karena operator penugasan memiliki evaluasi kanan-ke-kiri (misalnya a = b = c = d) ... sehingga orang dapat membayangkan bahwa + = mengikuti aturan yang sama, sebagai operasi atom (seperti yang saya lakukan dengan metode SetSum saya) ... tetapi yang terjadi sebenarnya adalah bahwa C # diterjemahkan a += bmenjadi a = a + b... menunjukkan bahwa operator + = bukan atom ... itu hanya gula sintaksis.
Miguel Angelo
30

Karena i++pertama mengembalikan nilai, lalu menambahkannya. Tetapi setelah saya diatur ke 1, Anda mengaturnya kembali ke 0.

Yuriy Faktorovich
sumber
17

Metode post-increment terlihat seperti ini

int ++(ref int i)
{
    int c = i;
    i = i + 1;
    return c;
}

Jadi pada dasarnya ketika Anda menelepon i++, iadalah kenaikan tetapi nilai asli dikembalikan dalam kasus Anda 0 dikembalikan.

Ash Burlaczenko
sumber
12

Jawaban sederhana

int i = 0;
i += i++;
// Translates to:
i = i + 0; // because post increment returns the current value 0 of i
// Before the above operation is set, i will be incremented to 1
// Now i gets set after the increment,
// so the original returned value of i will be taken.
i = 0;
Praveen Kumar Purushothaman
sumber
12

i ++ berarti: mengembalikan nilai i THEN increment it.

i + = i ++ berarti: Ambil nilai i saat ini. Tambahkan hasil i ++.

Sekarang, mari kita tambahkan i = 0 sebagai kondisi awal. i + = i ++ sekarang dievaluasi seperti ini:

  1. Berapa nilai saya saat ini? Ini 0. Simpan sehingga kita dapat menambahkan hasil i ++ ke dalamnya.
  2. Mengevaluasi i ++ (mengevaluasi ke 0 karena itulah nilai saat ini dari i)
  3. Muat nilai yang disimpan dan tambahkan hasil langkah 2 ke dalamnya. (tambahkan 0 hingga 0)

Catatan: Pada akhir langkah 2, nilai i sebenarnya adalah 1. Namun, pada langkah 3, Anda membuangnya dengan memuat nilai i sebelum ditambahkan.

Berbeda dengan i ++, ++ i mengembalikan nilai yang ditambahkan.

Karena itu, i + = ++ saya akan memberi Anda 1.

Carl
sumber
Ini adalah bantuan Full
sonsha
11

Operator kenaikan pos perbaikan ++,, memberikan variabel nilai dalam ekspresi dan kemudian melakukan kenaikan yang Anda tetapkan mengembalikan nol (0) nilai untuk ilagi yang menimpa yang bertambah satu (1) , sehingga Anda mendapatkan nol. Anda dapat membaca lebih lanjut tentang operator kenaikan di ++ Operator (MSDN).

Adil
sumber
8

i += i++;akan sama dengan nol, karena ia melakukan ++sesudahnya.

i += ++i; akan melakukannya sebelumnya

Wes Cossick
sumber
4
Jika tidak ++setelah itu, saya harapkan hasilnya 1.
comecme
8

++ postfix mengevaluasi isebelum menambahkannya, dan +=hanya mengevaluasi isekali.

Oleh karena itu, 0 + 0 = 0, seperti iyang dievaluasi dan digunakan sebelum ditambahkan, sebagai format postfix ++digunakan. Untuk mendapatkan ipeningkatan terlebih dahulu, gunakan formulir awalan ( ++i).

(Juga, hanya sebuah catatan: Anda hanya akan mendapatkan 1, karena 0 + (0 + 1) = 1)

Referensi: http://msdn.microsoft.com/en-us/library/sa7629ew.aspx (+ =)
http://msdn.microsoft.com/en-us/library/36x43w8w.aspx (++)

Nate Koppenhaver
sumber
8

Apa yang dilakukan C #, dan "mengapa" kebingungan itu

Saya juga mengharapkan nilainya menjadi 1 ... tetapi beberapa eksplorasi tentang hal itu mengklarifikasi beberapa poin.

Karena metode berikut:

    static int SetSum(ref int a, int b) { return a += b; }

    static int Inc(ref int a) { return a++; }

Saya berharap itu i += i++sama dengan SetSum(ref i, Inc(ref i)). Nilai i setelah pernyataan ini adalah 1 :

int i = 0;
SetSum(ref i, Inc(ref i));
Console.WriteLine(i); // i is 1

Tapi kemudian saya sampai pada kesimpulan lain ... i += i++sebenarnya sama dengan i = i + i++... jadi saya telah membuat contoh serupa lainnya, menggunakan fungsi-fungsi ini:

    static int Sum(int a, int b) { return a + b; }

    static int Set(ref int a, int b) { return a = b; }

Setelah memanggil ini Set(ref i, Sum(i, Inc(ref i)))nilai i adalah 0 :

int i = 0;
Set(ref i, Sum(i, Inc(ref i)));
Console.WriteLine(i); // i is 0

Ini tidak hanya menjelaskan apa yang dilakukan C # ... tetapi juga mengapa banyak orang bingung dengan hal itu ... termasuk saya.

Miguel Angelo
sumber
2
Harap tambahkan ini ke jawaban asli Anda, itu tidak menambah manfaat untuk menjadikannya sebagai jawaban yang terpisah.
casperOne
2
Saya melakukan ini untuk tidak mencemari jawaban yang lain, karena ini adalah tentang kode yang diuraikan ... sementara yang ini, saya mencoba pendekatan yang berbeda untuk menjelaskan sesuatu. Bagaimana menurut anda? Haruskah saya mengedit jawaban yang lain dan menambahkan yang ini? Mungkin, tambahkan yang ini ... tidak tahu! Terima kasih atas sarannya!
Miguel Angelo
7

Mnemonik yang baik yang selalu saya ingat tentang ini adalah sebagai berikut:

Jika ++berdiri setelah ekspresi, itu mengembalikan nilai seperti sebelumnya . Jadi kode berikut

int a = 1;
int b = a++;

adalah 1, karena aitu 1 sebelum naik setelah++ berdiri . Orang-orang menyebut notasi perbaikan pos ini . Ada juga notasi pre fix, di mana semuanya justru sebaliknya: jika berdiri sebelumnya , ekspresi mengembalikan nilai setelah operasi: a++

int a = 1;
int b = ++a;

b ada dua di sini.

Jadi untuk kode Anda, ini artinya

int i = 0;
i += (i++);

i++mengembalikan 0 (seperti dijelaskan di atas), jadi 0 + 0 = 0.

i += (++i); // Here 'i' would become two

Scott Meyers menjelaskan perbedaan antara kedua notasi dalam "pemrograman C ++ Efektif". Secara internal, i++(postfix) mengingat nilai itadi, dan memanggil awalan-notasi ( ++i) dan mengembalikan nilai yang lama i,. Inilah sebabnya mengapa Anda harus allways menggunakan ++idi forloop (meskipun saya pikir semua kompiler modern menerjemahkan i++ke ++idalam forloop).

Carsten
sumber
1
Saya diuji int i = 0; i += (++i), dan idiatur ke satu daripada dua. Masuk akal untuk saya juga, karena menggunakan awalan bukan postfix tidak mengubah fakta bahwa, jika Anda menulis i += (++i)untuk i = i + (++i), yang idievaluasi sebelum ++i, mengakibatkan i = 0 + (++i)dan akhirnya i = 0 + 1.
Wutz
6

Satu-satunya jawaban untuk pertanyaan Anda yang benar adalah: Karena itu tidak terdefinisi.

Ok, sebelum kalian semua membakar aku ..

Anda semua menjawab mengapa i+=i++boleh dan logis untuk menghasilkan i=0.

Saya tergoda untuk memberikan suara untuk setiap 1 dari jawaban Anda tetapi reputasi yang saya hitung akan terlalu tinggi ..

Kenapa aku sangat marah pada kalian? bukan karena apa jawaban Anda menjelaskan ..
Maksud saya, setiap jawaban yang saya baca telah melakukan upaya luar biasa untuk menjelaskan yang tidak mungkin, saya Tepuk Tangan!

Tapi apa hasilnya ?? apakah ini hasil yang intuitif - apakah ini hasil yang dapat diterima ??

Anda masing-masing melihat "raja telanjang" dan entah bagaimana menerimanya sebagai raja yang rasional.

Anda semua salah!

i+=i++; menghasilkan 0 tidak terdefinisi.

bug dalam mekanisme evaluasi bahasa jika Anda mau .. atau lebih buruk lagi! bug dalam desain.

ingin bukti? tentu saja kamu mau!

int t=0; int i=0; t+=i++; //t=0; i=1

Sekarang ini ... adalah hasil yang intuitif! karena kami pertama kali mengevaluasit memberinya nilai dan hanya setelah evaluasi dan penugasan kami memiliki operasi pasca terjadi - rasional bukan?

apakah itu rasional: i=i++dan i=imenghasilkan hasil yang sama untuki ?

sementara t=i++dan t=imemiliki hasil berbeda untuki .

Operasi pos adalah sesuatu yang harus terjadi setelah evaluasi pernyataan.
Karena itu:

int i=0;
i+=i++;

Seharusnya sama jika kita menulis:

int i=0;
i = i + i ++;

dan karena itu sama dengan:

int i=0;
i= i + i;
i ++;

dan karena itu sama dengan:

int i=0;
i = i + i;
i = i + 1;

Hasil apa pun yang tidak 1 menunjukkan bug dalam kompilator atau bug dalam desain bahasa jika kita menggunakan pemikiran rasional - namun MSDN dan banyak sumber lain memberi tahu kita "hei - ini tidak terdefinisi!"

Sekarang, sebelum saya melanjutkan, bahkan set contoh yang saya berikan ini tidak didukung atau diakui oleh siapa pun .. Namun inilah yang menurut cara intuitif dan rasional seharusnya hasilnya.

Pembuat kode harus tidak memiliki pengetahuan tentang bagaimana majelis sedang ditulis atau diterjemahkan!

Jika ditulis dengan cara yang tidak akan menghormati definisi bahasa - itu adalah bug!

Dan untuk menyelesaikannya, saya menyalin ini dari Wikipedia, operator increment dan decrement :
Karena operator increment / decrement memodifikasi operandnya, penggunaan operan semacam itu lebih dari sekali dalam ekspresi yang sama dapat menghasilkan hasil yang tidak ditentukan . Misalnya, dalam ekspresi seperti x - ++ x, tidak jelas dalam urutan apa operator pengurangan dan penambahan harus dilakukan. Situasi seperti ini menjadi lebih buruk ketika optimasi diterapkan oleh kompiler, yang dapat mengakibatkan urutan pelaksanaan operasi menjadi berbeda dari apa yang diinginkan oleh programmer.

Dan oleh karena itu.

Jawaban yang benar adalah bahwa ini TIDAK HARUS DIGUNAKAN! (karena itu TIDAK DITETAPKAN!)

Ya .. - Ini memiliki hasil yang tidak dapat diprediksi bahkan jika C # complier mencoba menormalkannya.

Saya tidak menemukan dokumentasi C # yang menjelaskan perilaku yang Anda semua dokumentasikan sebagai perilaku bahasa yang normal atau terdefinisi dengan baik. Apa yang saya temukan justru sebaliknya!

[ disalin dari dokumentasi MSDN untuk Operator Peningkatan dan Penurunan Postfix: ++ dan - ]

Ketika operator postfix diterapkan ke argumen fungsi, nilai argumen tidak dijamin akan bertambah atau dikurangi sebelum diteruskan ke fungsi. Lihat bagian 1.9.17 dalam standar C ++ untuk informasi lebih lanjut.

Perhatikan kata-kata itu tidak dijamin ...

Maafkan saya jika jawaban itu tampak sombong - saya bukan orang yang sombong. Saya hanya mempertimbangkan bahwa ribuan orang datang ke sini untuk belajar dan jawaban yang saya baca akan menyesatkan mereka dan akan merusak logika dan pemahaman mereka tentang subjek tersebut.

GY
sumber
Saya tidak yakin saya mengikuti 100%, tetapi Anda merujuk dokumentasi C ++, tetapi pertanyaan saya adalah tentang C #. Dokumentasi tentang itu ada di sini .
Peter
Saya merujuk ke C # dalam jawaban saya. Dari tautan yang Anda berikan: Hasil x ++ atau x-- adalah nilai x sebelum operasi, sedangkan hasil ++ x atau --x adalah nilai x setelah operasi. Dalam kedua kasus, x itu sendiri memiliki nilai yang sama setelah operasi. jelas menunjukkan ini bukan kasus saat pengujian .. karena i=++iakan memberikan hasil yang berbeda dari i=i++. Karena itu jawaban saya tetap.
GY
Aha, ok, tapi membingungkan karena Anda merujuk dokumentasi C ++. Jadi yang Anda katakan adalah bahwa spesifikasi belum diterapkan dengan benar?
Peter
Tidak. Apa yang saya katakan adalah bahwa itu tidak terdefinisi sesuai dengan spesifikasi, dan menggunakan undefined akan berakhir pada hasil yang tidak ditentukan.
GY
Tidak terdefinisi dalam C ++, tetapi C # mengatakan itu harus memiliki nilai yang sama setelah operasi , bukan? Itu tidak sama dengan tidak terdefinisi (tapi saya setuju Anda tidak boleh menggunakannya, lihat penafian saya, saya hanya mencoba memahami apa yang terjadi).
Peter
4

Operator ++ setelah variabel membuatnya menjadi kenaikan postfix. Penambahan terjadi setelah semua hal lain dalam pernyataan, penambahan dan penugasan. Jika sebaliknya, Anda meletakkan ++ sebelum variabel, itu akan terjadi sebelum nilai i dievaluasi, dan memberi Anda jawaban yang diharapkan.

KeithS
sumber
2
The ++tidak terjadi setelah itu +=pernyataan, itu terjadi selama pelaksanaan +=pernyataan. Karena itulah efek dari ++getride oleh +=.
dtb
Menggunakan ++ saya benar-benar menghasilkan 1, bukan 2 (awalnya 'jawaban yang diharapkan' saya).
Peter
Sepertinya tugas += menimpa modifikasi karena kenaikan sebelum atau sesudah dalam ekspresi.
Steven Lu
4

Langkah-langkah dalam perhitungan adalah:

  1. int i=0 // Diinisialisasi ke 0
  2. i+=i++ //Persamaan
  3. i=i+i++ // setelah menyederhanakan persamaan dengan kompiler
  4. i=0+i++ // saya menghargai substitusi
  5. i=0+0 // i ++ adalah 0 seperti yang dijelaskan di bawah ini
  6. i=0 // Hasil akhir i = 0

Di sini, awalnya nilai iadalah 0. WKT, i++tidak lain adalah: pertama-tama gunakan inilai dan kemudian tambahkan inilainya dengan 1. Jadi menggunakan inilainya, 0, saat menghitung i++dan kemudian menambahkannya dengan 1. Jadi menghasilkan nilai dari 0.

Suresh M
sumber
3

Ada dua opsi:

Opsi pertama: jika kompiler membaca pernyataan sebagai berikut,

i++;
i+=i;

maka hasilnya adalah 2.

Untuk

else if
i+=0;
i++;

hasilnya 1.

NEO
sumber
5
Tidak ada yang merupakan hasil aktual .
Steven Lu
3

Berhati-hatilah: baca FAQ C : apa yang Anda coba lakukan (mencampur tugas dan ++variabel yang sama) tidak hanya tidak ditentukan, tetapi juga tidak ditentukan (artinya kompiler dapat melakukan apa saja saat mengevaluasi !, tidak hanya memberi hasil "masuk akal").

Silakan baca, bagian 3 . Seluruh bagian ini layak dibaca! Terutama 3.9, yang menjelaskan implikasi yang tidak ditentukan. Bagian 3.3 memberi Anda ringkasan singkat tentang apa yang Anda bisa, dan tidak bisa lakukan, dengan "i ++" dan sejenisnya.

Bergantung pada internal kompiler, Anda mungkin mendapatkan 0, atau 2, atau 1, atau bahkan yang lainnya! Dan karena tidak terdefinisi, tidak apa-apa bagi mereka untuk melakukannya.

Olivier Dulac
sumber
oops, c # ... Saya terlempar oleh "gcc" beberapa melalui untuk membongkar kode.
Olivier Dulac
1
Aku rindu itu juga C #, tetapi tetap menyukai jawabannya.
Iain Collins
1
@ Iain: terima kasih, saya juga percaya itu layak untuk menjaga jawaban tetap tersedia, banyak orang tidak tahu tentang ini (atau tentang faq yang hebat itu , dari waktu terbaik Usenet di mana sebagian besar orang dengan pengetahuan tentang penaklukan akan sama. tempat untuk memperbaruinya)
Olivier Dulac
3

Ada banyak alasan bagus dalam jawaban di atas, saya hanya melakukan tes kecil dan ingin berbagi dengan Anda

int i = 0;
i+ = i++;

Di sini hasil saya menunjukkan hasil 0. Sekarang pertimbangkan kasus di bawah ini:

Kasus 1:

i = i++ + i; //Answer 1

sebelumnya saya pikir kode di atas menyerupai ini sehingga pada awalnya terlihat jawaban adalah 1, dan jawaban saya untuk yang ini adalah 1.

Kasus 2:

i = i + i++; //Answer 0 this resembles the question code.

di sini operator kenaikan tidak datang di jalur eksekusi, tidak seperti kasus sebelumnya di mana i ++ memiliki kesempatan untuk mengeksekusi sebelum penambahan.

Saya harap ini sedikit membantu. Terima kasih

ThomasBecker
sumber
2

Berharap untuk menjawab ini dari tipe pemrograman C 101 perspektif.

Sepertinya ini terjadi dalam urutan ini:

  1. idievaluasi sebagai 0, menghasilkan i = 0 + 0operasi kenaikan i++"antri", tetapi penugasan 0 untuk ibelum terjadi juga.
  2. Peningkatan i++terjadi
  3. Penugasan i = 0dari atas terjadi, secara efektif menimpa apa pun yang # 2 (setelah kenaikan) akan dilakukan.

Sekarang, # 2 mungkin tidak pernah benar-benar terjadi (mungkin tidak?) Karena kompiler mungkin menyadari itu tidak akan ada gunanya, tetapi ini bisa jadi tergantung kompiler. Bagaimanapun, jawaban lain yang lebih luas menunjukkan bahwa hasilnya benar dan sesuai dengan standar C #, tetapi tidak ditentukan apa yang terjadi di sini untuk C / C ++.

Bagaimana dan mengapa di luar keahlian saya, tetapi kenyataan bahwa penugasan sisi kanan yang sebelumnya dievaluasi terjadi setelah kenaikan pasca mungkin yang membingungkan di sini.

Selanjutnya, Anda tidak akan mengharapkan hasilnya menjadi 2 terlepas kecuali Anda melakukannya, ++ibukan i++saya percaya.

gkimsey
sumber
1
Versi preincrement menghasilkan hasil 2dengan C ++: ideone.com/8dH8tf
Steven Lu
Itu masuk akal. Tetapi pre-increment adalah situasi yang sedikit lebih rumit daripada post-increment.
gkimsey
2

Sederhananya,

i ++, akan menambahkan 1 ke "i" setelah operator "+ =" selesai.

Yang Anda inginkan adalah ++ i, sehingga akan menambahkan 1 ke "i" sebelum operator "+ =" dieksekusi.

seesharper
sumber
0
i=0

i+=i

i=i+1

i=0;

Kemudian angka 1 ditambahkan ke i.

i + = i ++

Jadi sebelum menambahkan 1 ke i, iambil nilai 0. Hanya jika kita menambahkan 1 sebelumnya, idapatkan nilai 0.

i+=++i

i=2
mempelajari apa
sumber
-4

Jawabannya adalah iakan1 .

Mari kita lihat caranya:

Mulanya i=0; .

Kemudian sambil menghitung i +=i++;sesuai dengan nilai kita akan memiliki sesuatu seperti 0 +=0++;, jadi menurut operator diutamakan 0+=0akan tampil pertama dan hasilnya akan0 .

Kemudian operator kenaikan akan diterapkan sebagaimana 0++, sebagaimana 0+1dan nilai iakan 1.

Shivam Sharma
sumber
3
Jawaban ini salah. Anda tidak akan mendapatkan 1 karena ketika Anda melakukan 0 += 0++;penugasan setelah kenaikan ++tetapi dengan nilai i ditafsirkan sebelum ++(karena adalah operator pos.
PhoneixS
2
Maaf, tapi ini tidak benar. Baca pertanyaan saya dan Anda akan melihat saya katakan hasilnya 0. Jika Anda menjalankan kode, Anda akan melihatnya efektif 0.
Peter