Ambil kode berikut (dapat digunakan sebagai Aplikasi Konsol):
static void Main(string[] args)
{
int i = 0;
i += i++;
Console.WriteLine(i);
Console.ReadLine();
}
Hasilnya i
adalah 0. Saya mengharapkan 2 (seperti yang dilakukan beberapa rekan saya). Mungkin kompiler membuat semacam struktur yang menghasilkan i
nol.
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.
i
pada sisi kiri dari+=
yang "cache" sebelum sisi kanan dievaluasi. Ini kontra-intuitif, karena akan, misalnya, memerlukan operasi penyalinan jikai
suatu objek. (Tolong jangan salah mengerti saya: Saya benar-benar setuju untuk menyatakan bahwa itu0
adalah jawaban yang benar dan sesuai standar.)Jawaban:
Ini:
Dapat dilihat seperti yang Anda lakukan (berikut ini adalah penyederhanaan berlebih):
Apa yang sebenarnya terjadi adalah lebih terlibat dari itu - lihatlah pada MSDN, 7.5.9 Peningkatan dan penurunan operator postfix :
Perhatikan bahwa karena urutan prioritas , postfix
++
terjadi sebelumnya+=
, tetapi hasilnya akhirnya tidak digunakan (seperti nilai sebelumnyai
yang 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, salinani
sebelum operasi berlangsung - satu untuk setiap operasi. (Saya akan menggunakan namaiAdd
daniAssign
untuk variabel sementara yang digunakan untuk++
dan+=
masing - masing).Jadi, perkiraan yang lebih dekat dengan apa yang terjadi adalah:
sumber
++
Operasi ini dilakukan sebelum evaluasi pernyataan selesai. Jadi+=
menimpa nilainya. Inikah yang terjadi?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.i+1
padahal seharusnyai=i+1
. Bukankah itu apai++
?Pembongkaran kode yang sedang berjalan:
Kode Setara
Ini mengkompilasi ke kode yang sama dengan kode berikut:
Pembongkaran kode kedua (hanya untuk membuktikan bahwa mereka sama)
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" :
a = i++ + i
yang kedua saya dipengaruhi oleh kenaikan tersebutFunc(i++, i)
yang kedua saya terpengaruh||
dan&&
:(false && i++ != i) || i == 0
yang ketiga saya tidak terpengaruh oleh i ++ karena tidak dievaluasiJadi apa arti dari:
i += i++;
?Itu sama dengan
i = i + i++;
Urutan evaluasi adalah:
Bukan berarti kenaikan itu dibuang.
Apa arti dari:
i = i++ + i;
?Ini tidak sama dengan contoh sebelumnya. Yang ke-3
i
dipengaruhi oleh kenaikan tersebut.Urutan evaluasi adalah:
sumber
a++ + a
tidak sama dengana + 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.dievaluasi sebagai berikut:
yaitu
i
diubah dua kali: sekali olehi++
ekspresi dan sekali oleh+=
pernyataan.Tetapi operan dari
+=
pernyataan itu adalahi
sebelum evaluasii++
(sisi kiri+=
) dani
sebelum evaluasii++
(sisi kanan+=
).sumber
Pertama,
i++
pengembalian 0. Kemudiani
ditambahkan oleh 1. Terakhiri
diatur ke nilai awali
yaitu 0 ditambah nilai yangi++
dikembalikan, yang juga nol. 0 + 0 = 0.sumber
i += i++;
tidaki = i++;
, jadi nilaii++
(0) ditambahkani
, dan tidak "i
diatur ke nilai yangi++
dikembalikan". Sekarang pertanyaannya adalah, ketika menambahkan nilai yangi++
dikembalikan kei
, akankahi
nilai bertambah atau nilai tidak bertambah? Jawabannya, temanku, tertulis dalam spesifikasi.i = 0
awalnya,i += something
sama dengani = 0 + something
yangi = something
.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.
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,i
yang dievaluasi baik sebagai sumber nilai, dan sebagai tempat menyimpan nilai. Operator mengevaluasii
, menemukan0
, dan akibatnya menyimpan a1
ke lokasi itu. Ini mengembalikan nilai sebelumnya,,0
sesuai dengan semantik mengembalikan nilai sebelumnya.Sekarang kontrol kembali ke
+=
operator. Sekarang memiliki semua info untuk menyelesaikan operasinya. Ia tahu tempat menyimpan hasil (lokasi penyimpanani
) serta nilai sebelumnya, dan memiliki nilai untuk ditambahkan ke nilai sebelumnya, yaitu0
. Jadi,i
berakhir 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.
sumber
SetSum(ref i, Inc(ref i))
denganint SetSum(ref int a, int b) { return a += b; }
danint Inc(ref int a) { return a++; }
... tentu saja saya tidak lagi mengharapkan itu.Set(ref i, Sum(i, Inc(ref i)))
denganint Set(ref int a, int b) { return a = b; }
danint Sum(int a, int b) { return a + b; }
.SetSum
adalah bahwa ia tidak mengevaluasi operan kirii
, tetapi hanya mengambil alamatnya, jadi itu tidak setara dengan evaluasi kiri dan kanan yang lengkap dari operan. Anda butuh sesuatu sepertiSetSum(ref i, i, PostInc(ref i))
. Argumen keduaSetSum
adalah nilai yang akan ditambahkan, di mana kita hanya menggunakani
untuk menentukan nilai sebelumnya darii
.SetSum
hanyaint SetSum(ref int dest, int a, int b) { return dest = a + b; }
.a += b
menjadia = a + b
... menunjukkan bahwa operator + = bukan atom ... itu hanya gula sintaksis.Karena
i++
pertama mengembalikan nilai, lalu menambahkannya. Tetapi setelah saya diatur ke 1, Anda mengaturnya kembali ke 0.sumber
Metode post-increment terlihat seperti ini
Jadi pada dasarnya ketika Anda menelepon
i++
,i
adalah kenaikan tetapi nilai asli dikembalikan dalam kasus Anda 0 dikembalikan.sumber
Jawaban sederhana
sumber
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:
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.
sumber
Operator kenaikan pos perbaikan
++
,, memberikan variabel nilai dalam ekspresi dan kemudian melakukan kenaikan yang Anda tetapkan mengembalikan nol (0) nilai untuki
lagi yang menimpa yang bertambah satu (1) , sehingga Anda mendapatkan nol. Anda dapat membaca lebih lanjut tentang operator kenaikan di ++ Operator (MSDN).sumber
i += i++;
akan sama dengan nol, karena ia melakukan++
sesudahnya.i += ++i;
akan melakukannya sebelumnyasumber
++
setelah itu, saya harapkan hasilnya1
.++ postfix mengevaluasi
i
sebelum menambahkannya, dan+=
hanya mengevaluasii
sekali.Oleh karena itu, 0 + 0 = 0, seperti
i
yang dievaluasi dan digunakan sebelum ditambahkan, sebagai format postfix++
digunakan. Untuk mendapatkani
peningkatan 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 (++)
sumber
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:
Saya berharap itu
i += i++
sama denganSetSum(ref i, Inc(ref i))
. Nilai i setelah pernyataan ini adalah 1 :Tapi kemudian saya sampai pada kesimpulan lain ...
i += i++
sebenarnya sama dengani = i + i++
... jadi saya telah membuat contoh serupa lainnya, menggunakan fungsi-fungsi ini:Setelah memanggil ini
Set(ref i, Sum(i, Inc(ref i)))
nilai i adalah 0 :Ini tidak hanya menjelaskan apa yang dilakukan C # ... tetapi juga mengapa banyak orang bingung dengan hal itu ... termasuk saya.
sumber
Mnemonik yang baik yang selalu saya ingat tentang ini adalah sebagai berikut:
Jika
++
berdiri setelah ekspresi, itu mengembalikan nilai seperti sebelumnya . Jadi kode berikutadalah 1, karena
a
itu 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
++
b
ada dua di sini.Jadi untuk kode Anda, ini artinya
i++
mengembalikan 0 (seperti dijelaskan di atas), jadi0 + 0 = 0
.Scott Meyers menjelaskan perbedaan antara kedua notasi dalam "pemrograman C ++ Efektif". Secara internal,
i++
(postfix) mengingat nilaii
tadi, dan memanggil awalan-notasi (++i
) dan mengembalikan nilai yang lamai
,. Inilah sebabnya mengapa Anda harus allways menggunakan++i
difor
loop (meskipun saya pikir semua kompiler modern menerjemahkani++
ke++i
dalamfor
loop).sumber
int i = 0; i += (++i)
, dani
diatur ke satu daripada dua. Masuk akal untuk saya juga, karena menggunakan awalan bukan postfix tidak mengubah fakta bahwa, jika Anda menulisi += (++i)
untuki = i + (++i)
, yangi
dievaluasi sebelum++i
, mengakibatkani = 0 + (++i)
dan akhirnyai = 0 + 1
.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 menghasilkani=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++;
menghasilkan0
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 mengevaluasi
t
memberinya nilai dan hanya setelah evaluasi dan penugasan kami memiliki operasi pasca terjadi - rasional bukan?apakah itu rasional:
i=i++
dani=i
menghasilkan hasil yang sama untuki
?sementara
t=i++
dant=i
memiliki hasil berbeda untuki
.Operasi pos adalah sesuatu yang harus terjadi setelah evaluasi pernyataan.
Karena itu:
Seharusnya sama jika kita menulis:
dan karena itu sama dengan:
dan karena itu sama dengan:
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.
sumber
i=++i
akan memberikan hasil yang berbeda darii=i++
. Karena itu jawaban saya tetap.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.
sumber
++
tidak terjadi setelah itu+=
pernyataan, itu terjadi selama pelaksanaan+=
pernyataan. Karena itulah efek dari++
getride oleh+=
.+=
menimpa modifikasi karena kenaikan sebelum atau sesudah dalam ekspresi.Langkah-langkah dalam perhitungan adalah:
int i=0
// Diinisialisasi ke 0i+=i++
//Persamaani=i+i++
// setelah menyederhanakan persamaan dengan kompileri=0+i++
// saya menghargai substitusii=0+0
// i ++ adalah 0 seperti yang dijelaskan di bawah inii=0
// Hasil akhir i = 0Di sini, awalnya nilai
i
adalah 0. WKT,i++
tidak lain adalah: pertama-tama gunakani
nilai dan kemudian tambahkani
nilainya dengan 1. Jadi menggunakani
nilainya, 0, saat menghitungi++
dan kemudian menambahkannya dengan 1. Jadi menghasilkan nilai dari 0.sumber
Ada dua opsi:
Opsi pertama: jika kompiler membaca pernyataan sebagai berikut,
maka hasilnya adalah 2.
Untuk
hasilnya 1.
sumber
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.
sumber
Ada banyak alasan bagus dalam jawaban di atas, saya hanya melakukan tes kecil dan ingin berbagi dengan Anda
Di sini hasil saya menunjukkan hasil 0. Sekarang pertimbangkan kasus di bawah ini:
Kasus 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:
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
sumber
Berharap untuk menjawab ini dari tipe pemrograman C 101 perspektif.
Sepertinya ini terjadi dalam urutan ini:
i
dievaluasi sebagai 0, menghasilkani = 0 + 0
operasi kenaikani++
"antri", tetapi penugasan 0 untuki
belum terjadi juga.i++
terjadii = 0
dari 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,
++i
bukani++
saya percaya.sumber
2
dengan C ++: ideone.com/8dH8tfSederhananya,
i ++, akan menambahkan 1 ke "i" setelah operator "+ =" selesai.
Yang Anda inginkan adalah ++ i, sehingga akan menambahkan 1 ke "i" sebelum operator "+ =" dieksekusi.
sumber
Kemudian angka 1 ditambahkan ke
i
.i + = i ++
Jadi sebelum menambahkan 1 ke
i
,i
ambil nilai 0. Hanya jika kita menambahkan 1 sebelumnya,i
dapatkan nilai 0.sumber
Jawabannya adalah
i
akan1
.Mari kita lihat caranya:
Mulanya
i=0;
.Kemudian sambil menghitung
i +=i++;
sesuai dengan nilai kita akan memiliki sesuatu seperti0 +=0++;
, jadi menurut operator diutamakan0+=0
akan tampil pertama dan hasilnya akan0
.Kemudian operator kenaikan akan diterapkan sebagaimana
0++
, sebagaimana0+1
dan nilaii
akan1
.sumber
0 += 0++;
penugasan setelah kenaikan++
tetapi dengan nilai i ditafsirkan sebelum++
(karena adalah operator pos.