Mengapa x = x ++ tidak terdefinisi?


19

Itu tidak terdefinisi karena ia memodifikasi xdua kali antara titik urutan. Standar mengatakan itu tidak terdefinisi, oleh karena itu tidak terdefinisi.
Setahu saya itu.

Tapi kenapa?

Pemahaman saya adalah bahwa melarang hal ini memungkinkan kompiler untuk mengoptimalkan dengan lebih baik. Ini bisa masuk akal ketika C ditemukan, tetapi sekarang sepertinya argumen yang lemah.
Jika kita menemukan kembali C hari ini, apakah kita akan melakukannya dengan cara ini, atau dapatkah itu dilakukan dengan lebih baik?
Atau mungkin ada masalah yang lebih dalam, yang membuatnya sulit untuk mendefinisikan aturan yang konsisten untuk ekspresi seperti itu, jadi yang terbaik adalah melarangnya?

Jadi misalkan kita menciptakan kembali C hari ini. Saya ingin menyarankan aturan sederhana untuk ekspresi seperti x=x++, yang menurut saya bekerja lebih baik daripada aturan yang ada.
Saya ingin mendapatkan pendapat Anda tentang aturan yang disarankan dibandingkan dengan yang ada, atau saran lainnya.

Aturan yang Disarankan:

  1. Di antara titik-titik urutan, urutan evaluasi tidak ditentukan.
  2. Efek samping segera terjadi.

Tidak ada perilaku tidak jelas yang terlibat. Ekspresi mengevaluasi nilai ini atau itu, tetapi pasti tidak akan memformat hard disk Anda (anehnya, saya belum pernah melihat implementasi di mana x=x++memformat hard disk).

Contoh Ekspresi

  1. x=x++- Didefinisikan dengan baik, tidak berubah x.
    Pertama, xditambahkan (segera ketika x++dievaluasi), lalu nilai lamanya disimpan x.

  2. x++ + ++x- Peningkatan xdua kali, dievaluasi menjadi 2*x+2.
    Meskipun kedua sisi dapat dievaluasi terlebih dahulu, hasilnya adalah x + (x+2)(sisi kiri terlebih dahulu) atau (x+1) + (x+1)(sisi kanan terlebih dahulu).

  3. x = x + (x=3)- Tidak ditentukan, xdiatur ke salah satu x+3atau 6.
    Jika sisi kanan dievaluasi dulu, itu x+3. Mungkin juga x=3dievaluasi dulu, jadi begitu 3+3. Dalam kedua kasus, x=3penugasan terjadi segera ketika x=3dievaluasi, sehingga nilai yang disimpan ditimpa oleh penugasan lain.

  4. x+=(x=3)- Didefinisikan dengan baik, set xke 6.
    Anda bisa berpendapat bahwa ini hanya singkatan untuk ungkapan di atas.
    Tetapi saya akan mengatakan bahwa itu +=harus dieksekusi setelah x=3, dan tidak dalam dua bagian (baca x, evaluasi x=3, tambahkan, dan simpan nilai baru).

Apa Keuntungannya?

Beberapa komentar mengangkat poin bagus ini.
Saya tentu tidak berpikir ekspresi seperti x=x++harus digunakan dalam kode normal apa pun.
Sebenarnya, aku jauh lebih ketat dari itu - saya pikir penggunaan hanya baik untuk x++sebagai x++;saja.

Namun, saya pikir aturan bahasanya harus sesederhana mungkin. Kalau tidak, programmer tidak akan memahaminya. aturan yang melarang mengubah variabel dua kali antara titik urut tentu saja merupakan aturan yang kebanyakan programmer tidak mengerti.

Aturan yang sangat mendasar adalah ini:
Jika A valid, dan B valid, dan digabungkan dengan cara yang valid, hasilnya valid.
xadalah nilai-L yang valid, x++apakah ekspresi yang valid, dan =apakah cara yang valid untuk menggabungkan nilai-L dan ekspresi, jadi mengapa x=x++tidak sah?
Standar C membuat pengecualian di sini, dan pengecualian ini memperumit aturan. Anda dapat mencari stackoverflow.com dan melihat seberapa banyak pengecualian ini membingungkan orang.
Jadi saya katakan - singkirkan kebingungan ini.

=== Ringkasan Jawaban ===

  1. Kenapa melakukan itu?
    Saya mencoba menjelaskan pada bagian di atas - Saya ingin aturan C menjadi sederhana.

  2. Potensi untuk pengoptimalan:
    Ini memang membutuhkan kebebasan dari kompiler, tetapi saya tidak melihat apa pun yang meyakinkan saya bahwa itu mungkin signifikan.
    Sebagian besar optimasi masih bisa dilakukan. Misalnya, a=3;b=5;dapat dipesan ulang, meskipun standar menentukan pesanan. Ekspresi seperti a=b[i++]masih dapat dioptimalkan dengan cara yang sama.

  3. Anda tidak dapat mengubah standar yang ada.
    Saya akui, saya tidak bisa. Saya tidak pernah berpikir saya benar-benar dapat melanjutkan dan mengubah standar dan kompiler. Saya hanya ingin berpikir jika segala sesuatunya dapat dilakukan secara berbeda.


10
Mengapa ini penting bagi Anda? Haruskah hal itu didefinisikan, dan jika demikian, mengapa? Tidak ada gunanya menetapkan xuntuk dirinya sendiri, dan jika Anda ingin menambah xAnda bisa mengatakan x++;- tidak perlu untuk tugas itu. Saya akan mengatakannya tidak boleh didefinisikan hanya karena akan sulit untuk mengingat apa yang seharusnya terjadi.
Caleb

4
Dalam pikiran saya, ini adalah pertanyaan yang bagus ("Beberapa pria melihat hal-hal sebagaimana adanya dan bertanya mengapa, saya memimpikan hal-hal yang tidak pernah ada dan bertanya mengapa tidak"). Ini (menurut pendapat saya) pertanyaan murni pada desain bahasa, menggunakan sintaks C sebagai contoh, bukan pertanyaan pada sintaks C. Saya, secara pribadi, berpikir bahwa alasan kami tidak memiliki perilaku yang ditentukan untuk ekspresi seperti x ++ + ++ x atau x = x ++ hanya karena ada kemungkinan mereka salah membaca.
Jamie Taylor

5
@ugoren: Mengapa Anda perlu memprediksi hasilnya. Tidak ada orang waras yang akan menulis kode seperti itu (seperti yang telah disebutkan beberapa kali) bahkan jika Anda menulis kode seperti ini, kode itu akan ditolak pada ulasan kode pertama. Jadi tidak perlu mendefinisikan perilaku dan memberikan optimizer peluang terbaik untuk mengoptimalkannya. Dalam setiap contoh Anda mengusulkan saya akan menembak seseorang jika mereka menambahkannya ke basis kode.
Martin York

3
Saya akan menemukan pertanyaan yang lebih menarik mengapa tidak ada kesalahan untuk menulis ini? Tentunya seorang kompiler dapat mendeteksi itu perilaku yang tidak terdefinisi dan karena itu tidak mungkin menjadi apa yang sebenarnya diinginkan pengguna, jadi mengapa tidak ada kesalahan? Saya memahami beberapa contoh bahavour terdefinisi sulit dideteksi tapi ini isn; t
JohnB

3
" aturan yang melarang mengubah variabel dua kali antara titik-titik urutan tentu saja merupakan aturan yang kebanyakan programmer tidak mengerti. " - Apakah Anda memiliki bukti untuk ini? Sebagian besar pertanyaan yang saya lihat ditanyakan karena programmer tidak tahu aturannya. Adakah bukti bahwa sebagian besar dari mereka masih belum memahaminya setelah dijelaskan?
Aman

Jawaban:


24

Mungkin Anda harus menjawab pertanyaan pertama mengapa harus didefinisikan? Apakah ada keuntungan dalam gaya pemrograman, keterbacaan, pemeliharaan atau kinerja dengan memungkinkan ekspresi seperti itu dengan efek samping tambahan? Adalah

y = x++ + ++x;

lebih mudah dibaca daripada

y = 2*x + 2;
x += 2;

Mengingat bahwa perubahan seperti itu sangat mendasar dan melanggar basis kode yang ada.


1
Saya menambahkan bagian "mengapa" ke pertanyaan saya. Saya tentu tidak menyarankan menggunakan ungkapan-ungkapan ini, tetapi saya tertarik memiliki aturan sederhana untuk mengatakan arti dari ekspresi.
ugoren

Juga, perubahan ini tidak merusak kode yang ada, kecuali jika itu memanggil perilaku tidak terdefinisi. Koreksi saya jika saya salah.
ugoren

3
Jawaban yang lebih filosofis: Saat ini tidak terdefinisi. Jika tidak ada programmer yang menggunakannya, maka tidak perlu bagi Anda untuk memahami ekspresi seperti itu, karena seharusnya tidak ada kode apa pun. Jika ada kebutuhan bagi Anda untuk memahaminya, maka jelas harus ada banyak kode di luar sana yang bergantung pada perilaku yang tidak terdefinisi. ;)
Aman

1
Secara definisi, ini tidak melanggar basis kode apa pun yang ada untuk mendefinisikan perilaku. Jika mereka mengandung UB, mereka, menurut definisi, sudah rusak.
DeadMG

1
@ugoren: Bagian "mengapa" Anda masih belum menjawab pertanyaan praktis: mengapa Anda ingin ungkapan aneh ini dalam kode Anda? Jika Anda tidak dapat menemukan jawaban yang meyakinkan untuk itu, maka seluruh diskusi dapat diperdebatkan.
Mike Baranczak

20

Argumen yang membuat perilaku tidak terdefinisi ini memungkinkan optimalisasi yang lebih baik adalah tidak lemah hari ini. Bahkan, hari ini jauh lebih kuat daripada saat C masih baru.

Ketika C masih baru, mesin yang bisa memanfaatkan ini untuk optimasi yang lebih baik sebagian besar model teoritis. Orang-orang telah berbicara tentang kemungkinan membangun CPU di mana kompiler akan menginstruksikan CPU tentang instruksi apa yang bisa / harus dieksekusi secara paralel dengan instruksi lainnya. Mereka menunjuk fakta bahwa membiarkan ini memiliki perilaku yang tidak terdefinisi berarti bahwa pada CPU seperti itu, jika memang benar-benar ada, Anda dapat menjadwalkan bagian "kenaikan" dari instruksi untuk dieksekusi secara paralel dengan sisa aliran instruksi. Sementara mereka benar tentang teorinya, pada saat itu ada sedikit perangkat keras yang benar-benar dapat mengambil keuntungan dari kemungkinan ini.

Itu bukan hanya teori lagi. Sekarang ada perangkat keras dalam produksi, dan digunakan secara luas, (misalnya, Itanium, VLIW DSP) yang benar - benar dapat mengambil keuntungan dari ini. Mereka benar - benar melakukannya memungkinkan kompiler untuk menghasilkan aliran instruksi yang menentukan bahwa instruksi X, Y dan Z semuanya dapat dieksekusi secara paralel. Ini bukan lagi model teoritis - ini adalah perangkat keras nyata yang digunakan secara nyata untuk melakukan pekerjaan nyata.

IMO, membuat perilaku yang didefinisikan ini dekat dengan "solusi" terburuk untuk masalah ini. Anda jelas tidak boleh menggunakan ekspresi seperti ini. Untuk sebagian besar kode, perilaku ideal adalah kompilator hanya menolak ekspresi seperti itu sepenuhnya. Pada saat itu, kompiler C tidak melakukan analisis aliran yang diperlukan untuk mendeteksi hal itu secara andal. Bahkan pada saat standar C asli, itu masih sama sekali tidak umum.

Saya tidak yakin itu akan dapat diterima oleh komunitas saat ini juga - sementara banyak kompiler dapat melakukan analisis aliran semacam itu, mereka biasanya hanya melakukannya ketika Anda meminta optimasi. Saya ragu sebagian besar pemrogram akan menyukai ide memperlambat "debug" build hanya demi dapat menolak kode yang mereka (waras) tidak akan pernah menulis di tempat pertama.

Apa yang telah dilakukan C adalah pilihan terbaik kedua yang semi-masuk akal: beri tahu orang-orang untuk tidak melakukan itu, mengizinkan (tetapi tidak mengharuskan) kompiler untuk menolak kode. Ini menghindari (masih lebih jauh) memperlambat kompilasi untuk orang-orang yang tidak pernah menggunakannya, tetapi masih memungkinkan seseorang untuk menulis kompiler yang akan menolak kode tersebut jika mereka ingin (dan / atau memiliki bendera yang akan menolaknya sehingga orang dapat memilih untuk menggunakan atau tidak sesuai keinginan mereka).

Setidaknya IMO, membuat perilaku yang didefinisikan ini akan (setidaknya mendekati) keputusan terburuk yang mungkin dibuat. Pada perangkat keras gaya VLIW, pilihan Anda adalah menghasilkan kode yang lebih lambat untuk penggunaan yang wajar dari operator increment, hanya demi kode jelek yang melecehkan mereka, atau selalu memerlukan analisis aliran yang luas untuk membuktikan bahwa Anda tidak berurusan dengan kode jelek, sehingga Anda dapat menghasilkan kode lambat (serial) hanya jika benar-benar diperlukan.

Intinya: jika Anda ingin menyembuhkan masalah ini, Anda harus berpikir sebaliknya. Alih-alih mendefinisikan apa yang dilakukan kode seperti itu, Anda harus mendefinisikan bahasa sehingga ungkapan seperti itu tidak diperbolehkan sama sekali (dan hidup dengan kenyataan bahwa sebagian besar programmer mungkin akan memilih kompilasi yang lebih cepat daripada menegakkan persyaratan itu).


IMO, ada sedikit alasan untuk percaya bahwa dalam kebanyakan kasus, instruksi yang lebih lambat benar-benar jauh lebih lambat daripada instruksi cepat dan bahwa ini akan selalu berdampak pada kinerja program. Saya akan kelas yang satu ini di bawah optimasi prematur.
DeadMG

Mungkin saya kehilangan sesuatu - jika tidak ada orang yang seharusnya menulis kode seperti itu, mengapa peduli untuk mengoptimalkannya?
ugoren

1
@ugoren: menulis kode seperti a=b[i++];(misalnya) baik-baik saja, dan mengoptimalkannya adalah hal yang baik. Saya tidak, bagaimanapun, melihat titik melukai kode yang masuk akal seperti itu sehingga sesuatu seperti ++i++memiliki makna yang jelas.
Jerry Coffin

2
@ugoren Masalahnya adalah salah satu diagnosis. Satu-satunya tujuan untuk tidak langsung melarang ekspresi seperti ++i++tepatnya adalah bahwa pada umumnya sulit untuk membedakannya dari ekspresi yang valid dengan efek samping (seperti a=b[i++]). Ini mungkin tampak cukup sederhana bagi kita, tetapi jika saya mengingat Buku Naga dengan benar maka itu sebenarnya merupakan masalah yang sulit. Karena itulah perilaku ini adalah UB, bukan dilarang.
Konrad Rudolph

1
Saya tidak percaya bahwa kinerja adalah argumen yang valid. Saya berjuang untuk percaya bahwa kasus ini cukup umum, mengingat perbedaan yang sangat tipis dan eksekusi yang sangat cepat dalam kedua kasus, untuk penurunan kinerja kecil menjadi nyata - belum lagi bahwa pada banyak prosesor dan arsitektur, mendefinisikannya gratis secara efektif.
DeadMG

9

Eric Lippert, seorang desainer utama di tim C # compiler, memposting di blognya sebuah artikel tentang sejumlah pertimbangan yang masuk ke dalam memilih untuk membuat fitur yang tidak terdefinisi pada tingkat spesifikasi bahasa. Jelas C # adalah bahasa yang berbeda, dengan faktor yang berbeda masuk ke dalam desain bahasanya, tetapi poin yang ia buat tetap relevan.

Secara khusus, ia menunjukkan masalah memiliki kompiler yang ada untuk bahasa yang memiliki implementasi yang sudah ada dan juga memiliki perwakilan di komite. Saya tidak yakin apakah itu yang terjadi di sini, tetapi cenderung relevan dengan sebagian besar diskusi spesifikasi terkait C dan C ++.

Yang juga perlu diperhatikan adalah, seperti yang Anda katakan, potensi kinerja untuk optimisasi kompiler. Meskipun benar bahwa kinerja CPU hari ini banyak urutan besarnya lebih besar daripada ketika C masih muda, sejumlah besar pemrograman C dilakukan hari ini dilakukan secara spesifik karena potensi peningkatan kinerja, dan potensi untuk (masa depan hipotetis) ) Optimalisasi instruksi CPU dan optimisasi pemrosesan multicore akan konyol untuk dicegah karena serangkaian aturan yang terlalu ketat untuk menangani efek samping dan titik urutan.


Dari artikel yang Anda tautkan, sepertinya C # tidak jauh dari apa yang saya sarankan. Urutan efek samping didefinisikan "ketika diamati dari utas yang menyebabkan efek samping". Saya tidak menyebutkan multi-threading, tetapi secara umum C tidak menjamin banyak untuk pengamat di utas lain.
ugoren

5

Pertama, mari kita lihat definisi perilaku yang tidak terdefinisi:

3.4.3

1 perilaku
perilaku yang tidak terdefinisi, pada saat menggunakan konstruksi program yang tidak dapat diakses atau salah atau data yang salah, yang oleh standar internasional ini tidak ada persyaratan

2. karakteristik cara lingkungan yang terdokumentasi (dengan atau tanpa penerbitan pesan diagnostik), untuk mengakhiri terjemahan atau eksekusi (dengan penerbitan pesan diagnostik).

3 CONTOH Contoh perilaku yang tidak ditentukan adalah perilaku pada aliran bilangan bulat

Jadi dengan kata lain, "perilaku tidak terdefinisi" hanya berarti bahwa kompiler bebas untuk menangani situasi dengan cara apa pun yang diinginkannya, dan tindakan semacam itu dianggap "benar".

Akar masalah yang dibahas adalah klausa berikut:

6.5 Ekspresi

...
3 Pengelompokan operator dan operan ditunjukkan oleh sintaks. 74) Kecuali sebagaimana tercantum ed kemudian (untuk fungsi panggilan (), &&, ||, ?:, dan operator koma), urutan evaluasi subexpressions dan urutan di mana efek samping berlangsung keduanya unspeci fi ed .

Penekanan ditambahkan.

Diberi ekspresi seperti

x = a++ * --b / (c + ++d);

yang subexpressions a++, --b, c, dan ++ddapat dievaluasi dalam urutan apapun . Selanjutnya, efek samping dari a++,, --bdan ++ddapat diterapkan pada titik mana pun sebelum titik urutan berikutnya (TKI, bahkan jika a++dievaluasi sebelumnya --b, itu tidak dijamin yang aakan diperbarui sebelum --bdievaluasi). Seperti yang dikatakan orang lain, alasan perilaku ini adalah untuk memberikan implementasi kebebasan untuk mengatur ulang operasi secara optimal.

Karena itu, bagaimanapun, ekspresi suka

x = x++
y = i++ * i++
a[i] = i++
*p++ = -*p    // this one bit me just yesterday

dll., akan menghasilkan hasil yang berbeda untuk implementasi yang berbeda (atau untuk implementasi yang sama dengan pengaturan optimasi yang berbeda, atau berdasarkan pada kode di sekitarnya, dll.).

Perilaku dibiarkan tidak terdefinisi sehingga kompiler tidak memiliki kewajiban untuk "melakukan hal yang benar", apa pun itu. Kasus-kasus di atas cukup mudah untuk ditangkap, tetapi ada sejumlah kasus non-sepele yang akan sulit untuk ditangkap pada waktu kompilasi.

Jelas, Anda dapat merancang bahasa sedemikian rupa sehingga urutan evaluasi dan urutan di mana efek samping diterapkan secara ketat, dan Java dan C # melakukannya, sebagian besar untuk menghindari masalah yang mengarah pada definisi C dan C ++.

Jadi, mengapa perubahan ini tidak dilakukan pada C setelah 3 revisi standar? Pertama-tama, ada kode C warisan selama 40 tahun di luar sana, dan tidak dijamin bahwa perubahan seperti itu tidak akan merusak kode itu. Ini menempatkan sedikit beban pada penulis kompiler, karena perubahan seperti itu akan segera membuat semua kompiler yang ada tidak sesuai; setiap orang harus membuat penulisan ulang yang signifikan. Dan bahkan pada CPU modern yang cepat, masih mungkin untuk mewujudkan keuntungan kinerja nyata dengan mengutak-atik urutan evaluasi.


1
Penjelasan yang sangat bagus tentang masalah ini. Saya tidak setuju tentang melanggar aplikasi lawas - cara perilaku tidak terdefinisi / tidak spesifik diterapkan kadang-kadang perubahan antara versi kompiler, tanpa ada perubahan dalam standar. Saya tidak menyarankan untuk mengubah perilaku yang didefinisikan.
ugoren

4

Pertama, Anda harus memahami bahwa bukan hanya x = x ++ yang tidak ditentukan. Tidak ada yang peduli dengan x = x ++, karena apa pun yang Anda definisikan, tidak ada gunanya. Apa yang tidak terdefinisi lebih seperti "a = b ++ di mana a dan b kebetulan sama" - yaitu

void f(int *a, int *b) {
    *a = (*b)++;
}
int i;
f(&i, &i);

Ada beberapa cara berbeda fungsi dapat diimplementasikan, tergantung pada apa yang paling efisien untuk arsitektur prosesor (dan untuk pernyataan di sekitarnya, dalam hal ini adalah fungsi yang lebih kompleks daripada contoh). Misalnya, dua yang jelas:

load r1 = *b
copy r2 = r1
increment r1
store *b = r1
store *a = r2

atau

load r1 = *b
store *a = r1
increment r1
store *b = r1

Perhatikan bahwa yang pertama terdaftar di atas, yang menggunakan lebih banyak instruksi dan lebih banyak register, adalah yang Anda perlukan untuk digunakan dalam semua kasus di mana a dan b tidak dapat dibuktikan berbeda.


Anda memang menunjukkan kasus di mana saran saya menghasilkan lebih banyak operasi mesin, tetapi tampaknya tidak berarti bagi saya. Dan kompiler masih memiliki kebebasan - satu-satunya persyaratan nyata yang saya tambahkan adalah untuk menyimpan bsebelumnya a.
ugoren

3

Warisan

Asumsi bahwa C dapat diciptakan kembali hari ini tidak dapat diterima. Ada begitu banyak baris kode C yang telah diproduksi dan digunakan setiap hari, sehingga mengubah aturan permainan di tengah permainan itu salah.

Tentu saja Anda dapat menciptakan bahasa baru, katakanlah C + = , dengan aturan Anda. Tapi itu tidak akan menjadi C.


2
Saya tidak benar-benar berpikir kita dapat menemukan kembali C hari ini. Ini tidak berarti kita tidak dapat membahas masalah ini. Namun, apa yang saya sarankan tidak benar-benar menciptakan kembali. Mengubah perilaku tidak terdefinisi menjadi didefinisikan atau tidak ditentukan dapat dilakukan ketika memperbarui standar, dan bahasa akan tetap C.
ugoren

2

Menyatakan bahwa sesuatu didefinisikan tidak akan mengubah kompiler yang ada untuk menghormati definisi Anda. Itu terutama benar dalam kasus asumsi yang mungkin telah diandalkan secara eksplisit atau implisit di banyak tempat.

Masalah utama untuk asumsi ini bukan dengan x = x++;(kompiler dapat dengan mudah memeriksanya dan harus memperingatkan), itu dengan *p1 = (*p2)++dan setara ( p1[i] = p2[j]++;ketika p1 dan p2 adalah parameter untuk suatu fungsi) di mana kompiler tidak dapat mengetahui dengan mudah jika p1 == p2(dalam C99 restricttelah ditambahkan untuk menyebarkan kemungkinan mengasumsikan p1! = p2 di antara titik-titik urutan, sehingga dianggap bahwa kemungkinan pengoptimalan itu penting).


Saya tidak melihat bagaimana saran saya mengubah apa pun yang berkaitan dengannya p1[i]=p2[j]++. Jika kompilator dapat menganggap tidak ada alias, tidak ada masalah. Jika tidak bisa, itu harus pergi dengan buku - kenaikan p2[j]dulu, simpan p1[i]nanti. Kecuali untuk peluang optimasi yang hilang, yang sepertinya tidak signifikan, saya tidak melihat masalah.
ugoren

Paragraf kedua tidak independen dari yang pertama, tetapi contoh dari jenis tempat di mana asumsi dapat merangkak masuk dan akan sulit dilacak.
Pemrogram

Paragraf pertama menyatakan sesuatu yang sangat jelas - kompiler harus diubah untuk memenuhi standar baru. Saya tidak benar-benar berpikir saya memiliki kesempatan untuk membakukan ini dan membuat penulis kompiler mengikuti. Saya pikir ini layak untuk dibahas.
ugoren

Masalahnya bukan bahwa kita perlu mengubah kompiler tentang perubahan dalam bahasa yang dibutuhkan, itu adalah bahwa perubahan itu meresap dan sulit ditemukan. Pendekatan yang paling praktis mungkin akan mengubah format perantara di mana pengoptimal bekerja, yaitu berpura-pura yang x = x++;belum ditulis tetapi t = x; x++; x = t;atau x=x; x++;atau apa pun yang Anda inginkan sebagai semantik (tetapi bagaimana dengan diagnostik?). Untuk bahasa baru, cukup hilangkan efek samping.
Pemrogram

Saya tidak tahu terlalu banyak tentang struktur kompiler. Jika saya benar-benar ingin mengubah semua kompiler, saya akan lebih peduli. Tetapi mungkin memperlakukan x++sebagai titik urutan, seolah-olah itu adalah panggilan fungsi inc_and_return_old(&x)akan melakukan trik.
ugoren

-1

Dalam beberapa kasus, kode semacam ini didefinisikan dalam Standar C ++ 11 yang baru.


5
Mau menguraikan?
ugoren

Saya pikir x = ++xsekarang didefinisikan dengan baik (tetapi tidak x = x++)
MM
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.