Bagaimana cara kerja operator koma di C ++?
Misalnya, jika saya lakukan:
a = b, c;
Apakah akhirnya sama dengan b atau c?
(Ya, saya tahu ini mudah untuk diuji - hanya mendokumentasikan di sini agar seseorang dapat menemukan jawabannya dengan cepat.)
Pembaruan: Pertanyaan ini telah memunculkan nuansa ketika menggunakan operator koma. Hanya untuk mendokumentasikan ini:
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
Pertanyaan ini sebenarnya terinspirasi oleh salah ketik kode. Apa yang dimaksudkan
a = b;
c = d;
Berubah menjadi
a = b, // <- Note comma typo!
c = d;
c++
comma-operator
Joe Schneider
sumber
sumber
a = (b, c);
.a = b, c = d;
benar-benar melakukan hal yang sama seperti yang dimaksudkana = b; c = d;
?b
dand
merupakan evaluasi fungsi yang menggunakan (dan memodifikasi) keadaan umum, urutan eksekusi tidak ditentukan hinggaC++17
.Jawaban:
Itu akan sama dengan
b
.Operator koma memiliki prioritas lebih rendah dari penugasan.
sumber
Berhati-hatilah untuk memperhatikan bahwa operator koma mungkin kelebihan beban dalam C ++. Perilaku yang sebenarnya mungkin sangat berbeda dari yang diharapkan.
Sebagai contoh, Boost.Spirit menggunakan operator koma dengan cukup cerdik untuk mengimplementasikan inisialisasi daftar untuk tabel simbol. Dengan demikian, ini membuat sintaks berikut ini mungkin dan bermakna:
Perhatikan bahwa karena prioritas operator, kode ini (sengaja!) Identik dengan
Yaitu, operator pertama yang dipanggil adalah
keywords.operator =("and")
yang mengembalikan objek proxy tempat sisanyaoperator,
dipanggil:sumber
char[]
, yang tidak dapat kelebihan beban. Kode tersebut pertama-tama secara sengaja memanggiloperator=
dan kemudianoperator,
untuk setiap elemen yang tersisa.Operator koma memiliki prioritas lebih rendah dari semua operator C / C ++. Oleh karena itu selalu yang terakhir untuk mengikat ekspresi, artinya:
setara dengan:
Fakta menarik lainnya adalah bahwa operator koma memperkenalkan titik urutan . Ini berarti ungkapan:
dijamin memiliki tiga subekspresi ( a + b , c () dan d ) dievaluasi secara berurutan. Ini penting jika mereka memiliki efek samping. Biasanya kompiler diizinkan untuk mengevaluasi subekspresi dalam urutan apa pun yang mereka anggap cocok; misalnya, dalam panggilan fungsi:
argumen dapat dievaluasi dalam urutan sewenang-wenang. Perhatikan bahwa koma dalam panggilan fungsi bukanlah operator; mereka adalah pemisah.
sumber
,
memiliki prioritas rendah, bahkan tertinggal di belakang itu sendiri ;) ... Yaitu: koma-sebagai- operator memiliki prioritas lebih rendah daripada koma-sebagai- pemisah . Jadi, jika Anda ingin menggunakan koma-sebagai- operator dalam argumen fungsi tunggal, penugasan variabel, atau daftar yang dipisahkan lainnya - maka Anda perlu menggunakan tanda kurung, misalnya:int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
Operator koma:
Versi default dari operator koma didefinisikan untuk semua jenis (built-in dan custom), dan berfungsi sebagai berikut - diberikan
exprA , exprB
:exprA
dievaluasiexprA
diabaikanexprB
dievaluasiexprB
dikembalikan sebagai hasil dari seluruh ekspresiPada sebagian besar operator, kompiler diperbolehkan untuk memilih urutan eksekusi dan bahkan diharuskan untuk melewatkan eksekusi apa pun jika tidak mempengaruhi hasil akhir (mis.
false && foo()
Akan melewatkan panggilan kefoo
). Namun ini bukan kasus untuk operator koma dan langkah-langkah di atas akan selalu terjadi * .Dalam praktiknya, operator koma default bekerja dengan cara yang hampir sama dengan titik koma. Perbedaannya adalah bahwa dua ekspresi yang dipisahkan oleh tanda titik koma membentuk dua pernyataan yang terpisah, sedangkan pemisahan koma menjadikan semua sebagai satu ekspresi. Inilah sebabnya mengapa operator koma kadang-kadang digunakan dalam skenario berikut:
if( HERE )
for
loopfor ( HERE ; ; )
if (foo) HERE ;
(tolong jangan lakukan itu, itu benar-benar jelek!)Saat pernyataan bukan ekspresi, titik koma tidak bisa diganti dengan koma. Misalnya ini tidak diizinkan:
(foo, if (foo) bar)
(if
bukan ekspresi)Dalam kasus Anda, kami memiliki:
a=b, c;
, setara dengana=b; c;
, dengan asumsi bahwa itua
adalah tipe yang tidak membebani operator koma.a = b, c = d;
setara dengana=b; c=d;
, dengan asumsi bahwa itua
adalah tipe yang tidak membebani operator koma.Perhatikan bahwa tidak setiap koma sebenarnya adalah operator koma. Beberapa koma yang memiliki arti yang sangat berbeda:
int a, b;
--- daftar deklarasi variabel dipisahkan oleh koma, tetapi ini bukan operator komaint a=5, b=3;
--- ini juga merupakan daftar deklarasi variabel yang dipisahkan komafoo(x,y)
--- daftar argumen yang dipisahkan koma. Bahkan,x
dany
bisa dievaluasi dalam urutan apa pun !FOO(x,y)
--- daftar argumen makro yang dipisahkan komafoo<a,b>
--- daftar argumen templat yang dipisahkan komaint foo(int a, int b)
--- daftar parameter yang dipisahkan komaFoo::Foo() : a(5), b(3) {}
--- daftar initializer yang dipisahkan koma dalam konstruktor kelas* Ini tidak sepenuhnya benar jika Anda menerapkan optimasi. Jika kompiler mengakui bahwa bagian kode tertentu sama sekali tidak berdampak pada yang lain, itu akan menghapus pernyataan yang tidak perlu.
Bacaan lebih lanjut: http://en.wikipedia.org/wiki/Comma_operator
sumber
operator ,
kelebihan beban Anda kehilangan jaminan pada associativity (sama seperti Anda kehilangan sifat hubung singkat darioperator&&
danoperator||
jika mereka kelebihan beban)?a, b, c
selalu berarti(a, b), c
dan tidak pernaha, (b, c)
. Penafsiran yang terakhir bahkan dapat menyebabkan kesalahan kompilasi jika elemen-elemennya berbeda jenis. Apa yang mungkin Anda kejar adalah urutan evaluasi argumen? Saya tidak yakin tentang itu, tapi mungkin Anda benar: itu bisa terjadi yangc
dievaluasi sebelum(a, b)
bahkan jika koma kiri-asosiatif.struct Foo { Foo() : a(5), b(3) {} int b; int a; }
mengevakuasib(3)
sebelumnyaa(5)
. Hal ini penting jika daftar Anda adalah seperti:Foo() : a(5), b(a) {}
. b tidak akan diatur ke 5, melainkan nilai yang tidak diinisialisasi dari a, yang mungkin atau mungkin tidak diperingatkan oleh kompiler Anda.Nilai
a
akanb
, tetapi nilai ekspresi akanc
. Yaitu dia akan sama dengan
b
, dand
akan sama denganc
.sumber
a = b; d = c;
?Nilai b akan ditugaskan ke a. Tidak ada yang akan terjadi pada c
sumber
Nilai a akan sama dengan b, karena operator koma memiliki prioritas lebih rendah dari operator penugasan.
sumber
Ya Operator koma memiliki prioritas lebih rendah dari operator Penugasan
Output: i = 3
Karena operator koma selalu mengembalikan nilai paling kanan.
Dalam hal operator koma dengan Operator Penugasan:
Ouput: i = 1
Seperti yang kita tahu operator koma memiliki prioritas lebih rendah daripada penugasan .....
sumber
i = 1;
pada baris itu?Hal pertama yang pertama: Koma sebenarnya bukan operator, untuk kompiler itu hanya token yang mendapat makna dalam konteks dengan token lain.
Apa artinya ini dan mengapa repot?
Contoh 1:
Untuk memahami perbedaan antara makna token yang sama dalam konteks yang berbeda, kita perhatikan contoh ini:
Biasanya pemula C ++ akan berpikir bahwa ungkapan ini dapat / akan membandingkan hal-hal tetapi absolutly salah, arti dari
<
,>
dan,
token bergantung pada konteks penggunaan.Penafsiran yang benar dari contoh di atas tentu saja merupakan contoh template.
Contoh 2:
Ketika kita menulis tipikal untuk loop dengan lebih dari satu variabel inisialisasi dan / atau lebih dari satu ekspresi yang harus dilakukan setelah setiap iterasi dari loop kita menggunakan koma juga:
Arti koma tergantung pada konteks penggunaan, di sini adalah konteks
for
konstruksi.Apa arti sebenarnya dari koma dalam konteks?
Untuk semakin memperumitnya (seperti biasa dalam C ++) operator koma itu sendiri dapat kelebihan beban (terima kasih kepada Konrad Rudolph karena menunjukkan hal itu).
Untuk kembali ke pertanyaan, Kode
berarti untuk sesuatu seperti kompiler
karena prioritas dari
=
tanda / operator lebih tinggi dari prioritas,
tanda.dan ini ditafsirkan dalam konteks like
(perhatikan bahwa interpretasi tergantung pada konteks, di sini itu bukan panggilan fungsi / metode atau instatiation template.)
sumber