Bagaimana cara kerja Operator Koma


175

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;


1
Kemungkinan rangkap dari apa yang dilakukan operator koma `,` di C? . Itu mengalahkan Anda satu hari. Dan jawaban lillq memberikan jawaban atas pertanyaan tentang a = (b, c);.
jww

5
Tetapi dalam hal ini a = b, c = d;benar-benar melakukan hal yang sama seperti yang dimaksudkan a = b; c = d;?
Bondolin

@NargothBond Belum tentu. Jika bdan dmerupakan evaluasi fungsi yang menggunakan (dan memodifikasi) keadaan umum, urutan eksekusi tidak ditentukan hingga C++17.
nyronium

Jawaban:


74

Itu akan sama dengan b.

Operator koma memiliki prioritas lebih rendah dari penugasan.


129

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:

keywords = "and", "or", "not", "xor";

Perhatikan bahwa karena prioritas operator, kode ini (sengaja!) Identik dengan

(((keywords = "and"), "or"), "not"), "xor";

Yaitu, operator pertama yang dipanggil adalah keywords.operator =("and")yang mengembalikan objek proxy tempat sisanya operator,dipanggil:

keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");

Umm, Anda tidak dapat mengubah prioritasnya, artinya Anda harus meletakkan tanda kurung di daftar Anda.
Jeff Burdges

18
@ Jeff Sebaliknya. Dengan tanda kurung di sekitar daftar ini tidak akan berfungsi sejak saat itu kompiler hanya melihat operator koma antara dua char[], yang tidak dapat kelebihan beban. Kode tersebut pertama-tama secara sengaja memanggil operator=dan kemudian operator,untuk setiap elemen yang tersisa.
Konrad Rudolph

125

Operator koma memiliki prioritas lebih rendah dari semua operator C / C ++. Oleh karena itu selalu yang terakhir untuk mengikat ekspresi, artinya:

a = b, c;

setara dengan:

(a = b), c;

Fakta menarik lainnya adalah bahwa operator koma memperkenalkan titik urutan . Ini berarti ungkapan:

a+b, c(), d

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:

someFunc(arg1, arg2, arg3)

argumen dapat dievaluasi dalam urutan sewenang-wenang. Perhatikan bahwa koma dalam panggilan fungsi bukanlah operator; mereka adalah pemisah.


15
Layak menunjukkan bahwa ,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;
underscore_d

68

Operator koma:

  • memiliki prioritas terendah
  • bersifat asosiatif kiri

Versi default dari operator koma didefinisikan untuk semua jenis (built-in dan custom), dan berfungsi sebagai berikut - diberikan exprA , exprB:

  • exprA dievaluasi
  • hasil exprAdiabaikan
  • exprB dievaluasi
  • hasil exprBdikembalikan sebagai hasil dari seluruh ekspresi

Pada 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 ke foo). 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:

  • Sintaks C membutuhkan ekspresi tunggal , bukan pernyataan. misalnya diif( HERE )
  • Sintaks C membutuhkan pernyataan tunggal, tidak lebih, misalnya dalam inisialisasi forloopfor ( HERE ; ; )
  • Ketika Anda ingin melewatkan kurung kurawal dan menyimpan satu pernyataan: 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)( ifbukan ekspresi)
  • int x, int y (deklarasi variabel bukan ekspresi)

Dalam kasus Anda, kami memiliki:

  • a=b, c;, setara dengan a=b; c;, dengan asumsi bahwa itu aadalah tipe yang tidak membebani operator koma.
  • a = b, c = d;setara dengan a=b; c=d;, dengan asumsi bahwa itu aadalah 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 koma
  • int a=5, b=3; --- ini juga merupakan daftar deklarasi variabel yang dipisahkan koma
  • foo(x,y)--- daftar argumen yang dipisahkan koma. Bahkan, xdan ybisa dievaluasi dalam urutan apa pun !
  • FOO(x,y) --- daftar argumen makro yang dipisahkan koma
  • foo<a,b> --- daftar argumen templat yang dipisahkan koma
  • int foo(int a, int b) --- daftar parameter yang dipisahkan koma
  • Foo::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


Apakah perlu dicatat bahwa jika operator ,kelebihan beban Anda kehilangan jaminan pada associativity (sama seperti Anda kehilangan sifat hubung singkat dari operator&&dan operator||jika mereka kelebihan beban)?
YoungJohn

Operator koma adalah asosiatif kiri terlepas dari apakah kelebihan beban atau tidak. Ekspresi a, b, cselalu berarti (a, b), cdan tidak pernah a, (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 yang cdievaluasi sebelum (a, b) bahkan jika koma kiri-asosiatif.
CygnusX1

1
Hanya sedikit komentar pada daftar inisialisasi yang dipisahkan koma dalam konstruktor kelas, urutan tidak ditentukan oleh posisi dalam daftar. Urutan ditentukan oleh posisi deklarasi kelas. Misalnya struct Foo { Foo() : a(5), b(3) {} int b; int a; }mengevakuasi b(3)sebelumnya a(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.
Jonathan Gawrych

Saya baru-baru ini menemukan operator koma dengan dua pelampung, apa gunanya mengevaluasi dan membuang nomor?
Aaron Franke

Saya tidak berpikir ada yang bisa menjawabnya. Anda harus menunjukkannya dalam konteks. Mungkin pertanyaan terpisah?
CygnusX1

38

Nilai aakan b, tetapi nilai ekspresi akan c. Yaitu di

d = (a = b, c);

a akan sama dengan b, dan dakan sama dengan c.


19
Hampir benar. Pernyataan tidak memiliki nilai, begitu ekspresi. Nilai dari ungkapan itu adalah c.
Leon Timmermans

Mengapa ini digunakan a = b; d = c;?
Aaron Franke

Ini membuat saya mengerti apa efek samping yang dibicarakan orang.
tali sepatu

8

Nilai b akan ditugaskan ke a. Tidak ada yang akan terjadi pada c


2

Nilai a akan sama dengan b, karena operator koma memiliki prioritas lebih rendah dari operator penugasan.


2

Ya Operator koma memiliki prioritas lebih rendah dari operator Penugasan

#include<stdio.h>
int main()
{
          int i;
          i = (1,2,3);
          printf("i:%d\n",i);
          return 0;
}

Output: i = 3
Karena operator koma selalu mengembalikan nilai paling kanan.
Dalam hal operator koma dengan Operator Penugasan:

 int main()
{
      int i;
      i = 1,2,3;
      printf("i:%d\n",i);
      return 0;
}

Ouput: i = 1
Seperti yang kita tahu operator koma memiliki prioritas lebih rendah daripada penugasan .....


Jadi, bagaimana contoh kedua berbeda dari hanya memiliki i = 1;pada baris itu?
Aaron Franke

-3

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:

class Example {
   Foo<int, char*> ContentA;
}

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:

for(a=5,b=0;a<42;a++,b--)
   ...

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

a = b, c;

berarti untuk sesuatu seperti kompiler

(a = b), c;

karena prioritas dari =tanda / operator lebih tinggi dari prioritas ,tanda.

dan ini ditafsirkan dalam konteks like

a = b;
c;

(perhatikan bahwa interpretasi tergantung pada konteks, di sini itu bukan panggilan fungsi / metode atau instatiation template.)


1
yakin itu, mungkin saya menggunakan terminologi yang salah (untuk lexer itu token, tentu saja)
Quonux

2
Ketika seseorang bekerja dengan operator, (sic), koma memang merupakan operator.
DragonLord

2
Meskipun mengenali jika tanda koma yang diberikan diakui sebagai operator koma (berlawanan dengan, misalnya, pemisah argumen) mungkin merupakan tantangan tersendiri, pertanyaan ini khususnya tentang operator koma .
CygnusX1
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.