Setelah membaca jawaban ini tentang perilaku dan urutan poin yang tidak ditentukan, saya menulis sebuah program kecil:
#include <stdio.h>
int main(void) {
int i = 5;
i = (i, ++i, 1) + 1;
printf("%d\n", i);
return 0;
}
Outputnya adalah 2
. Ya Tuhan, aku tidak melihat penurunan itu datang! Apa yang terjadi disini?
Juga, saat mengkompilasi kode di atas, saya mendapat peringatan yang mengatakan:
px.c: 5: 8: peringatan: operan kiri dari ekspresi koma tidak berpengaruh
[-Wunused-value] i = (i, ++i, 1) + 1; ^
Mengapa? Tetapi mungkin itu akan secara otomatis dijawab dengan jawaban dari pertanyaan pertama saya.
printf("2\n");
Jawaban:
Dalam ekspresi
(i, ++i, 1)
, koma yang digunakan adalah operator komaKarena membuang operan pertamanya, umumnya hanya berguna jika operan pertama memiliki efek samping yang diinginkan . Jika efek samping ke operan pertama tidak terjadi, maka kompiler dapat menghasilkan peringatan tentang ekspresi tanpa efek.
Jadi, dalam ungkapan di atas, yang paling kiri
i
akan dievaluasi dan nilainya akan dibuang. Kemudian++i
akan dievaluasi dan akan bertambahi
1 dan lagi nilai ekspresi++i
akan dibuang, tetapi efek sampingnyai
permanen . Kemudian1
akan dievaluasi dan nilai ekspresi akan1
.Ini setara dengan
Perhatikan bahwa ungkapan di atas adalah benar-benar valid dan tidak memunculkan perilaku tidak terdefinisi karena ada titik sekuen antara evaluasi operan kiri dan kanan operator koma.
sumber
i
diinisialisasi dengan5
. Lihatlah pernyataan deklarasiint i = 5;
.++i
, ungkapan ini akan dievaluasi,i
akan bertambah dan nilai kenaikan ini akan menjadi nilai ekspresi. Dalam hali++
, ekspresi ini akan dievaluasi, nilai lamai
akan menjadi nilai ekspresi,i
akan bertambah setiap saat antara titik urutan sebelumnya dan berikutnya dari ekspresi.Mengutip dari
C11
, bab6.5.17
, operator KomaJadi, dalam kasus Anda,
dievaluasi sebagai
i
, akan dievaluasi sebagai ekspresi batal, nilai dibuang++i
, akan dievaluasi sebagai ekspresi batal, nilai dibuang1
nilai kembali.Jadi, pernyataan terakhirnya seperti
dan
i
sampai2
. Saya kira ini menjawab kedua pertanyaan Anda,i
mendapat nilai 2?Catatan: FWIW, karena ada titik sekuens yang hadir setelah evaluasi operan kiri, ungkapan seperti
(i, ++i, 1)
tidak akan memanggil UB, karena orang mungkin berpikir secara tidak sengaja.sumber
i
jelas tidak berpengaruh! Namun, saya tidak berpikir itu sangat jelas bagi seorang pria yang tidak mengenal operator koma (dan saya tidak tahu bagaimana mencari bantuan, selain mengajukan pertanyaan). Sayang sekali saya mendapat banyak downvotes! Saya akan memeriksa jawaban lain dan kemudian memutuskan mana yang akan diterima. Terima kasih! Jawaban bagus btw.Mari kita menganalisa langkah demi langkah.
Jadi kita memperoleh 2. Dan tugas terakhir sekarang:
Apa pun yang ada di saya sebelum ditimpa sekarang.
sumber
++i
tidak berkontribusi pada hasil.int i = 0; for( ;(++i, i<max); )
Hasil dari
adalah
Untuk
evaluasi terjadi sedemikian rupa sehingga
,
operator membuang nilai yang dievaluasi dan akan mempertahankan nilai yang paling tepat1
Begitu
sumber
Anda akan menemukan bacaan yang bagus di halaman wiki untuk operator Comma .
Pada dasarnya itu
Ini artinya
pada gilirannya akan mengevaluasi
i
, membuang hasil, mengevaluasii++
, membuang hasil, dan kemudian mengevaluasi dan kembali1
.sumber
(void)exp; a= exp2;
sementara saya hanya perlua = exp, exp2;
)Anda perlu tahu apa yang dilakukan operator koma di sini:
Ekspresi Anda:
Ekspresi pertama,,
i
dievaluasi, ekspresi kedua++i
,, dievaluasi, dan ekspresi ketiga1
, dikembalikan untuk seluruh ekspresi.Jadi hasilnya adalah:
i = 1 + 1
.Untuk pertanyaan bonus Anda, seperti yang Anda lihat, ekspresi pertama
i
tidak berpengaruh sama sekali, jadi kompiler mengeluh.sumber
Koma memiliki prioritas 'terbalik'. Ini adalah apa yang akan Anda dapatkan dari buku-buku lama dan manual C dari IBM (70-an / 80-an). Jadi 'perintah' terakhir adalah apa yang digunakan dalam ekspresi orangtua.
Di C modern penggunaannya aneh tapi sangat menarik di C lama (ANSI):
Sementara semua operasi (fungsi) dipanggil dari kiri ke kanan, hanya ekspresi terakhir yang akan digunakan sebagai hasil untuk 'sementara' bersyarat. Ini mencegah penanganan 'goto's untuk menjaga blok unik dari perintah untuk dijalankan sebelum memeriksa kondisi.
EDIT: Ini menghindari juga panggilan ke fungsi penanganan yang bisa menangani semua logika di operan kiri dan mengembalikan hasil logis. Ingat bahwa, kami tidak memiliki fungsi sebaris di masa lalu C. Jadi, ini bisa menghindari panggilan overhead.
sumber