Saya melihat pertanyaan ini dalam sebuah tes di mana kita harus memberi tahu keluaran kode berikut.
#include<stdio.h>
int main(){
int k = 0;
while(+(+k--)!=0)
k=k++;
printf("%d\n", k);
return 0;
}
Outputnya adalah -1
. Saya tidak yakin mengapa ini jawabannya.
Apa arti ungkapan +(+k--)
dalam C?
k=k++
tidak terdefinisi, tetapi tidak terdefinisi karena tidak pernah dieksekusi karena kondisi yang dikaburkan - Saya memilih untuk menutup sebagai duplikat dari pertanyaan ini .Jawaban:
[Sebagai catatan, saya telah mengedit jawaban ini dengan cukup signifikan sejak diterima dan dipilih. Tapi pada dasarnya masih mengatakan hal yang sama.]
Kode ini sangat, mungkin sengaja, membingungkan. Ini berisi contoh sempit dari perilaku yang tidak terdefinisi ketakutan . Pada dasarnya tidak mungkin untuk menentukan apakah orang yang menyusun pertanyaan ini sangat, sangat pintar atau sangat, sangat bodoh. Dan "pelajaran" kode ini mungkin dimaksudkan untuk mengajarkan atau menanyai Anda tentang - yaitu, bahwa operator plus unary tidak berbuat banyak - tentu saja tidak cukup penting untuk pantas mendapatkan jenis penyesatan subversif semacam ini.
Ada dua aspek kode yang membingungkan, kondisi aneh:
dan pernyataan gila yang dikontrolnya:
Saya akan membahas bagian kedua terlebih dahulu.
Jika Anda memiliki variabel seperti
k
yang ingin Anda tambahkan 1, C memberi Anda bukan satu, bukan dua, bukan tiga, tetapi empat cara berbeda untuk melakukannya:k = k + 1
k += 1
++k
k++
Terlepas dari karunia ini (atau mungkin karena itu), beberapa programmer menjadi bingung dan batuk seperti contortions
Jika Anda tidak tahu apa yang harus dilakukan, jangan khawatir: tidak ada yang bisa. Ungkapan ini berisi dua upaya berbeda untuk mengubah
k
nilai (k =
bagian, dank++
bagian), dan karena tidak ada aturan dalam C untuk mengatakan mana dari percobaan modifikasi yang "menang", ungkapan seperti ini secara resmi tidak ditentukan , artinya tidak hanya itu telah ada didefinisikan arti, tetapi bahwa seluruh program yang berisi itu adalah tersangka.Sekarang, jika Anda melihat dengan sangat hati-hati, Anda akan melihat bahwa dalam program khusus ini, garis
k = k++
tidak benar-benar dieksekusi, karena (seperti yang akan kita lihat) kondisi pengendalian pada awalnya salah, sehingga loop berjalan 0 kali . Jadi program khusus ini mungkin sebenarnya tidak terdefinisi - tetapi masih membingungkan secara patologis.Lihat juga jawaban SO kanonik ini untuk semua pertanyaan tentang Perilaku Tidak Terdefinisi dari jenis ini.
Tetapi Anda tidak bertanya tentang
k=k++
bagian itu. Anda bertanya tentang bagian pertama yang membingungkan,+(+k--)!=0
kondisinya. Ini terlihat aneh, karena ini aneh. Tidak seorang pun akan pernah menulis kode seperti itu dalam program nyata. Jadi tidak ada alasan untuk belajar bagaimana memahaminya. (Ya, itu benar, menjelajahi batas-batas suatu sistem dapat membantu Anda belajar tentang poin-poin baiknya, tetapi ada garis yang cukup jelas dalam buku saya antara eksplorasi imajinatif, yang membangkitkan pikiran versus eksplorasi yang dangkal, eksplorasi yang kasar, dan ungkapan ini sangat jelas pada sisi yang salah dari garis itu.)Bagaimanapun, mari kita periksa
+(+k--)!=0
. (Dan setelah melakukannya, mari kita lupakan semuanya.) Ekspresi seperti ini harus dipahami dari dalam ke luar. Saya kira Anda tahu apatidak. Dibutuhkan
k
nilai saat ini dan "mengembalikan" ke seluruh ekspresi, dan kurang lebih secara bersamaan menurunk
, yaitu, ia menyimpan kuantitask-1
kembalik
.Tapi lalu apa fungsinya
+
? Ini plus unary , bukan plus biner. Ini seperti minus unary. Anda tahu bahwa minus biner tidak mengurangi: ekspresikurangi b dari a. Dan Anda tahu bahwa minus unary meniadakan hal-hal: ekspresi
memberi Anda negatif a. Yang
+
dilakukan unary adalah ... pada dasarnya tidak ada.+a
memberi Andaa
nilai, setelah mengubah nilai positif menjadi positif dan negatif menjadi negatif. Begitu ekspresinyamemberi Anda apa pun yang
k--
memberi Anda, itu adalahk
nilai lama.Tapi kita belum selesai, karena sudah
Ini hanya mengambil apa pun yang
+k--
memberi Anda, dan berlaku unary+
untuk itu lagi. Jadi itu memberi Anda apa pun yang+k--
memberi Anda, apa pun yangk--
memberi Anda, yang merupakank
nilai lama.Jadi pada akhirnya, kondisinya
melakukan hal yang persis sama dengan kondisi yang jauh lebih biasa
akan dilakukan. (Itu juga melakukan hal yang sama dengan kondisi yang terlihat lebih rumit
while(+(+(+(+k--)))!=0)
. Dan kurung itu tidak benar-benar diperlukan; itu juga melakukan hal yang sama seperti yangwhile(+ + + +k--!=0)
seharusnya dilakukan.)Bahkan mencari tahu apa kondisi "normal"
Apakah agak rumit. Ada dua hal yang terjadi dalam loop ini: Karena loop berpotensi berulang kali, kita akan:
k--
, untuk membuatk
lebih kecil dan lebih kecil, tetapi jugaTapi kami melakukan
k--
bagian itu segera, sebelum (atau dalam proses) memutuskan apakah akan melakukan perjalanan lain melalui loop. Dan ingat bahwak--
"mengembalikan" nilai lamak
, sebelum menurunkannya. Dalam program ini, nilai awalk
adalah 0. Jadik--
akan "mengembalikan" nilai lama 0, lalu memperbaruik
ke -1. Tapi kemudian kondisi lainnya adalah!= 0
- tetapi seperti yang baru saja kita lihat, pertama kali kita menguji kondisi, kita mendapat nilai 0. Jadi kita tidak akan melakukan perjalanan melalui loop, jadi kita tidak akan mencoba untuk mengeksekusi pernyataan bermasalahk=k++
sama sekali.Dengan kata lain, dalam loop khusus ini, meskipun saya mengatakan bahwa "ada dua hal yang terjadi", ternyata hal 1 terjadi satu kali, tetapi hal 2 terjadi nol kali.
Bagaimanapun, saya harap sekarang cukup jelas mengapa alasan yang buruk untuk program ini akhirnya mencetak -1 sebagai nilai akhir dari
k
. Biasanya, saya tidak suka menjawab pertanyaan kuis seperti ini - rasanya seperti curang - tetapi dalam kasus ini, karena saya sangat tidak setuju dengan seluruh poin latihan, saya tidak keberatan.sumber
Pada pandangan pertama sepertinya kode ini memanggil perilaku tidak terdefinisi namun itu tidak terjadi.
Pertama mari kita memformat kode dengan benar:
Jadi sekarang kita bisa melihat bahwa pernyataan itu
k=k++;
ada di dalam loop.Sekarang mari kita telusuri programnya:
Ketika kondisi loop pertama dievaluasi,
k
memiliki nilai 0. Ekspresik--
memiliki saat nilaik
, yang adalah 0, dank
decremented sebagai efek samping. Jadi setelah pernyataan ini nilainyak
-1.Garis depan
+
pada ungkapan ini tidak berpengaruh pada nilai, jadi+k--
dievaluasi ke 0 dan juga+(+k--)
dievaluasi ke 0.Kemudian
!=
operator dievaluasi. Karena0!=0
false, badan loop tidak dimasukkan . Seandainya tubuh dimasukkan, Anda akan memanggil perilaku yang tidak terdefinisi karenak=k++
keduanya membaca dan menulisk
tanpa titik urutan. Tetapi loop tidak dimasukkan, jadi tidak ada UB.Akhirnya nilai
k
dicetak yaitu -1.sumber
if (x != NULL) *x = 42;
Apakah ini tidak ditentukan kapanx == NULL
? Tentu saja tidak. Perilaku tidak terdefinisi tidak terjadi di bagian kode yang tidak dieksekusi. Kata perilaku adalah sebuah petunjuk. Kode yang tidak dieksekusi tidak memiliki perilaku, tidak terdefinisi atau sebaliknya.k=k++
secara kualitatif berbeda dari*x=42
. Yang terakhir didefinisikan dengan baik jikax
adalah pointer yang valid, tetapi yang pertama tidak terdefinisi apa pun yang terjadi. (Saya akui Anda mungkin benar, tetapi sekali lagi, saya tidak akan berdebat tentang hal itu, dan saya semakin khawatir kami telah dikuasai secara ahli.)Berikut ini adalah versi yang menunjukkan prioritas operator:
Dua
+
operator unary tidak melakukan apa-apa, jadi ungkapan ini persis sama dengank--
. Orang yang menulis ini kemungkinan besar mencoba mengacaukan pikiran Anda.sumber