Saat ini saya belajar C ++ dengan buku C ++ Primer dan salah satu latihan di buku ini adalah:
Jelaskan apa yang dilakukan ekspresi berikut:
someValue ? ++x, ++y : --x, --y
Apa yang kita ketahui? Kita tahu bahwa operator terner memiliki prioritas yang lebih tinggi daripada operator koma. Dengan operator biner, hal ini cukup mudah untuk dipahami, tetapi dengan operator terner saya sedikit kesulitan. Dengan operator biner "memiliki prioritas lebih tinggi" berarti kita dapat menggunakan tanda kurung di sekitar ekspresi dengan prioritas lebih tinggi dan itu tidak akan mengubah eksekusi.
Untuk operator terner, saya akan melakukan:
(someValue ? ++x, ++y : --x, --y)
secara efektif menghasilkan kode yang sama yang tidak membantu saya dalam memahami bagaimana kompilator akan mengelompokkan kode.
Namun, dari pengujian dengan compiler C ++ saya tahu bahwa ekspresi mengkompilasi dan saya tidak tahu apa yang :
bisa dipegang oleh operator dengan sendirinya. Jadi kompilator tampaknya menafsirkan operator terner dengan benar.
Kemudian saya menjalankan program dengan dua cara:
#include <iostream>
int main()
{
bool someValue = true;
int x = 10, y = 10;
someValue ? ++x, ++y : --x, --y;
std::cout << x << " " << y << std::endl;
return 0;
}
Hasil dalam:
11 10
Sedangkan di sisi lain dengan someValue = false
itu mencetak:
9 9
Mengapa compiler C ++ menghasilkan kode yang untuk cabang-benar dari operator terner hanya bertambah x
, sedangkan untuk cabang-palsu dari terner itu menurunkan keduanya x
dan y
?
Saya bahkan melangkah lebih jauh dengan menempatkan tanda kurung di sekitar cabang-asli seperti ini:
someValue ? (++x, ++y) : --x, --y;
tapi tetap saja hasilnya 11 10
.
sumber
?
adalah operator bersyarat . Istilah operator terner berarti operator dengan tiga operan. Operator bersyarat adalah salah satu contoh operator terner, tetapi suatu bahasa dapat (secara teoritis) memiliki beberapa operator terner.Jawaban:
Seperti yang dikatakan @Rakete dalam jawaban mereka yang luar biasa, ini rumit. Saya ingin menambahkan sedikit.
Operator terner harus berbentuk:
Jadi kami memiliki pemetaan berikut:
someValue
: logika-atau-ekspresi++x, ++y
: ekspresi--x, --y
atau hanya--x
?Sebenarnya ini hanya
--x
karena ekspresi tugas tidak dapat diurai sebagai dua ekspresi yang dipisahkan oleh koma (menurut aturan tata bahasa C ++), jadi--x, --y
tidak dapat diperlakukan sebagai ekspresi tugas .Yang menghasilkan bagian ekspresi terner (bersyarat) terlihat seperti ini:
Mungkin membantu demi keterbacaan untuk mempertimbangkan
++x,++y
untuk dihitung seolah-olah dalam tanda kurung(++x,++y)
; apa pun yang terkandung di antara?
dan:
akan diurutkan setelah bersyarat. (Saya akan memberi tanda kurung untuk sisa postingan).dan dievaluasi dalam urutan ini:
someValue?
(++x,++y)
atau--x
(tergantung padabool
hasil 1.)Ekspresi ini kemudian diperlakukan sebagai sub-ekspresi kiri ke operator koma, dengan sub-ekspresi kanan
--y
, seperti:Yang berarti sisi kiri adalah ekspresi nilai yang dibuang , artinya itu pasti dievaluasi, tetapi kemudian kami mengevaluasi sisi kanan dan mengembalikannya.
Jadi apa yang terjadi ketika
someValue
adalahtrue
?(someValue?(++x,++y):--x)
mengeksekusi dan meningkatkanx
dany
menjadi11
dan11
--y
yang kemudian menurunkany
kembali ke10
Untuk "memperbaiki" perilaku, Anda dapat mengelompokkan
--x, --y
dengan tanda kurung untuk mengubahnya menjadi ekspresi utama yang merupakan entri valid untuk ekspresi-tugas *:* Ini adalah rantai panjang yang agak lucu yang menghubungkan ekspresi penugasan kembali ke ekspresi utama:
assignment-expression --- (dapat terdiri dari) -> kondisional-ekspresi -> logika-atau-ekspresi -> logika-dan-ekspresi -> inklusif-atau-ekspresi -> eksklusif-atau-ekspresi - -> dan-ekspresi -> persamaan-ekspresi -> ekspresi-relasional -> ekspresi-pergeseran -> ekspresi-aditif -> ekspresi-perkalian -> ekspresi-pm -> ekspresi-cor -> unary-expression -> postfix-expression -> primary-expression
sumber
{ ... }
dapat diperlakukan sebagai ekspresi), saya sekarang memiliki jawaban => untuk menghindari keharusan memperkenalkan operator koma yang berperilaku sedemikian rumit.assignment-expression
rantai itu?Wow, itu rumit.
Kompilator melihat ekspresi Anda sebagai:
Operator terner membutuhkan a
:
, ia tidak dapat berdiri sendiri dalam konteks itu, tetapi setelah itu, tidak ada alasan mengapa koma harus menjadi bagian dari kasus palsu.Sekarang mungkin lebih masuk akal mengapa Anda mendapatkan keluaran itu. Jika
someValue
benar, maka++x
,++y
dan--y
dieksekusi, yang tidak secara efektif berubahy
tetapi menambahkan satu kex
.Jika
someValue
salah, maka--x
dan--y
dieksekusi, mengurangi keduanya satu per satu.sumber
Anda salah menafsirkan apa yang telah terjadi. Cabang sejati menambah
x
dany
. Namun,y
segera dikurangi setelah itu, tanpa syarat.Berikut adalah bagaimana hal ini terjadi: karena operator bersyarat memiliki prioritas yang lebih tinggi daripada operator koma di C ++ , kompilator mengurai ekspresi sebagai berikut:
Perhatikan "yatim piatu"
--y
setelah koma. Inilah yang menyebabkan penurunany
yang awalnya bertambah.Anda berada di jalur yang benar, tetapi Anda memberi tanda kurung pada cabang yang salah: Anda dapat memperbaikinya dengan memberi tanda kurung pada cabang lain, seperti ini:
Demo (cetakan 11 11)
sumber
Masalah Anda adalah ekspresi terner tidak benar-benar memiliki prioritas yang lebih tinggi daripada koma. Faktanya, C ++ tidak dapat dideskripsikan secara akurat hanya dengan didahulukan - dan ini persis interaksi antara operator terner dan koma di mana ia dipecah.
diperlakukan sebagai:
(koma berperilaku seolah-olah memiliki prioritas yang lebih tinggi). Di samping itu,
diperlakukan sebagai:
dan operator terner lebih diutamakan.
sumber
Poin yang terlewatkan dalam jawaban (meskipun disentuh pada komentar) adalah bahwa operator bersyarat selalu digunakan (dimaksudkan oleh desain?) Dalam kode nyata sebagai jalan pintas untuk menetapkan salah satu dari dua nilai ke variabel.
Jadi, konteks yang lebih besar adalah:
Yang tidak masuk akal di wajahnya, jadi kejahatannya bermacam-macam:
sumber
if
(misalnya, ekspresi kenaikan dalam untuk loop). Konteks yang lebih besar mungkinfor (x = 0, y=0; x+y < 100; someValue?(++x, ++y) :( --x, --y))
dengan loop yang dapat memodifikasix
dany
independen.