Apa hasil dari + = di C dan C ++?

93

Saya punya kode berikut:

#include <stdio.h>
int main(int argc, char **argv) {
    int i = 0;
    (i+=10)+=10;
    printf("i = %d\n", i);
    return 0;
}

Jika saya mencoba mengkompilasinya sebagai sumber C menggunakan gcc, saya mendapatkan kesalahan:

error: lvalue required as left operand of assignment

Tetapi jika saya mengkompilasinya sebagai sumber C ++ menggunakan g ++ saya tidak mendapatkan kesalahan dan ketika saya menjalankan yang dapat dieksekusi:

i = 20

Mengapa perilakunya berbeda?

Svetlin Mladenov
sumber
85
Beda bahasa, beda aturan sintaks ?. Secara pribadi, saya akan menolak kode itu dalam peninjauan kode.
Maks.
7
Hindari kode seperti ini imo ... Tidak jelas untuk semua orang.
allaire
1
Tidak diragukan lagi, kode tersebut tidak bersih dan harus dihindari dalam pengembangan "nyata". Namun demikian, saya mengamati perilaku yang sama dan ingin mengetahui alasannya.
ulidtko
9
Ini BUKAN kutipan kode dari perangkat lunak asli. Ini hanya masalah yang tidak sengaja saya temukan.
Svetlin Mladenov
3
@JohnDibling Saya pikir upvote secara khusus adalah (i + = 10) + = 10 Saya tidak tahu bahasa apa yang merupakan kode yang sah dan fakta bahwa dia mengatakan C ++ sebenarnya mengkompilasinya membuat saya penasaran.
Tony318

Jawaban:

133

Semantik dari operator penugasan majemuk berbeda di C dan C ++:

Standar C99, 6.5.16, bagian 3:

Operator penugasan menyimpan nilai dalam objek yang ditentukan oleh operan kiri. Ekspresi tugas memiliki nilai operan kiri setelah tugas, tetapi bukan nilai l.

Di C ++ 5.17.1:

Operator penugasan (=) dan operator penugasan gabungan semuanya grup dari kanan-ke-kiri. Semua membutuhkan nilai l yang dapat dimodifikasi sebagai operan kiri mereka dan mengembalikan nilai l dengan jenis dan nilai operan kiri setelah penugasan dilakukan.

EDIT: Perilaku (i+=10)+=10di C ++ tidak ditentukan di C ++ 98, tetapi didefinisikan dengan baik di C ++ 11. Lihat jawaban atas pertanyaan NPE ini untuk bagian yang relevan dari standar.

dasblinkenlight
sumber
Benar. Satu mengembalikan nilai hasil, dan satu mengembalikan variabel (alamat)
texasbruce
7
Penting : Perhatikan bahwa (i+=10)+=10perilaku tidak terdefinisi di C ++, lihat jawaban @aix.
David Rodríguez - dribeas
@ DavidRodríguez-dribeas Maksud Anda tidak ditentukan , bukan tidak ditentukan , bukan ?
dasblinkenlight
4
@dasblinkenlight: Tidak, maksudnya tidak terdefinisi . Dalam C ++ 03 dan sebelumnya, memodifikasi hasil nilai l dari ekspresi berperilaku tak terduga di semua kompiler karena kurangnya titik urutan intervensi. Jika tidak ditentukan , itu akan berperilaku dapat diprediksi tetapi berbeda pada kompiler yang berbeda .
Justin ᚅᚔᚈᚄᚒᚔ
2
Ini akan berguna dalam pengaturan seperti int f(int &y); f(x += 10);- meneruskan referensi ke variabel yang dimodifikasi ke dalam fungsi.
Phil Miller
51

Selain kode C tidak valid, baris

(i+=10)+=10;

akan menghasilkan perilaku yang tidak terdefinisi di C dan C ++ 03 karena akan berubah i dua kali di antara titik urutan.

Tentang mengapa itu diizinkan untuk dikompilasi di C ++:

[C ++ N3242 5.17.1] Operator penugasan (=) dan operator penugasan gabungan semua grup kanan-ke-kiri. Semua membutuhkan nilai l yang dapat dimodifikasi sebagai operan kiri dan mengembalikan nilai l yang merujuk ke operan kiri.

Paragraf yang sama selanjutnya mengatakan itu

Dalam semua kasus, penugasan diurutkan setelah penghitungan nilai dari operan kanan dan kiri, dan sebelum penghitungan nilai dari ekspresi penugasan.

Ini menunjukkan bahwa di C ++ 11, ekspresi tidak lagi memiliki perilaku yang tidak ditentukan.

NPE
sumber
3
Nah, ini pasti UB karena sequence pointnya. Ini juga kode yang tidak valid di C (tapi bukan C ++) tapi itu tidak terkait dengan poin urutan, dan harus ditangkap oleh kompilator.
Konrad Rudolph
2
@KonradRudolph: tidak, kompilator tidak berkewajiban untuk menangkap perilaku yang tidak terdefinisi, sebagai lawan dari kode yang salah bentuk. Bagian "harus ditangkap oleh kompiler" adalah hal yang tidak kami setujui.
2
Poin urutan tidak ada di C ++ 11, jadi alasan sebenarnya untuk UB adalah ada dua modifikasi iyang tidak diurutkan.
Mankarse
4
Ini salah bahwa ini adalah perilaku yang tidak terdefinisi. Jika penugasan tidak berurutan sebelum penghitungan nilai dari ekspresi penugasan, maka i = j+=1akan menghasilkan nilai yang tidak dapat ditentukan. Dari paragraf yang sama Anda mengutip "Dalam semua kasus, tugas diurutkan setelah penghitungan nilai operan kanan dan kiri, dan sebelum penghitungan nilai ekspresi penugasan." Oleh karena (i+=10)+=10itu didefinisikan dengan baik untuk dilakukan i += 10; i += 10;. Di sisi lain (i+=10)+=(i+=10)adalah UB.
bames53
2
Karena saya melihat ada beberapa ketidaksepakatan tentang ini di antara para pemberi komentar, saya telah memposting ini sebagai pertanyaan terpisah: stackoverflow.com/questions/10655290/…
NPE