C ++ 98 dan C ++ 03
Jawaban ini untuk versi standar C ++ yang lebih lama. Versi C ++ 11 dan C ++ 14 standar tidak secara formal mengandung 'poin urutan'; operasi 'diurutkan sebelum' atau 'tidak diurutkan' atau 'diurutkan tak tentu'. Efek bersihnya pada dasarnya sama, tetapi terminologinya berbeda.
Penafian : Oke. Jawaban ini agak panjang. Jadi bersabarlah saat membacanya. Jika Anda sudah tahu hal-hal ini, membacanya lagi tidak akan membuat Anda gila.
Prasyarat : Pengetahuan dasar tentang C ++ Standard
Apa itu Poin Urutan?
Standar mengatakan
Pada titik tertentu tertentu dalam urutan eksekusi yang disebut titik sekuens , semua efek samping dari evaluasi sebelumnya harus lengkap dan tidak ada efek samping dari evaluasi selanjutnya yang akan terjadi. (§1.9 / 7)
Efek samping? Apa efek sampingnya?
Evaluasi suatu ekspresi menghasilkan sesuatu dan jika selain itu ada perubahan dalam kondisi lingkungan eksekusi dikatakan bahwa ekspresi (evaluasinya) memiliki beberapa efek samping.
Sebagai contoh:
int x = y++; //where y is also an int
Selain operasi inisialisasi, nilai y
akan berubah karena efek samping dari ++
operator.
Sejauh ini bagus. Pindah ke titik urutan. Definisi pergantian poin seq yang diberikan oleh penulis comp.lang.c Steve Summit
:
Titik sekuens adalah titik di mana debu telah mengendap dan semua efek samping yang telah terlihat sejauh ini dijamin akan lengkap.
Apa titik urutan umum yang tercantum dalam Standar C ++?
Yaitu:
pada akhir evaluasi ekspresi penuh ( §1.9/16
) (Ekspresi penuh adalah ekspresi yang bukan merupakan subekspresi dari ekspresi lain.) 1
Contoh:
int a = 5; // ; is a sequence point here
dalam evaluasi masing-masing ekspresi berikut setelah evaluasi ekspresi pertama ( §1.9/18
) 2
a && b (§5.14)
a || b (§5.15)
a ? b : c (§5.16)
a , b (§5.18)
(di sini a, b adalah operator koma; di func(a,a++)
,
bukan operator koma, itu hanya pemisah antara argumen a
dan a++
. Dengan demikian perilaku tidak terdefinisi dalam kasus itu (jika a
dianggap sebagai tipe primitif))
pada panggilan fungsi (apakah fungsi inline atau tidak), setelah evaluasi semua argumen fungsi (jika ada) yang terjadi sebelum eksekusi ekspresi atau pernyataan apa pun di badan fungsi ( §1.9/17
).
1: Catatan: evaluasi ekspresi penuh dapat mencakup evaluasi subekspresi yang bukan bagian leksikal dari ekspresi penuh. Misalnya, subekspresi yang terlibat dalam mengevaluasi ekspresi argumen default (8.3.6) dianggap dibuat dalam ekspresi yang memanggil fungsi, bukan ekspresi yang mendefinisikan argumen default
2: Operator yang ditunjukkan adalah operator built-in, seperti yang dijelaskan dalam klausa 5. Ketika salah satu dari operator ini kelebihan beban (klausa 13) dalam konteks yang valid, dengan demikian menunjuk fungsi operator yang ditentukan pengguna, ekspresi menunjuk pada pemanggilan fungsi dan operan membentuk daftar argumen, tanpa titik urutan tersirat di antara mereka.
Apa itu Perilaku Tidak Terdefinisi?
Standar ini mendefinisikan Perilaku Tidak Terdefinisi dalam Bagian §1.3.12
sebagai
perilaku, seperti yang mungkin timbul pada saat penggunaan konstruksi program yang keliru atau data yang salah, yang untuknya Standar Internasional ini tidak menetapkan persyaratan 3 .
Perilaku tidak terdefinisi juga dapat diharapkan ketika Standar Internasional ini menghilangkan deskripsi dari setiap definisi perilaku yang eksplisit.
3: perilaku yang tidak terdefinisi yang diperbolehkan berkisar dari mengabaikan situasi sepenuhnya dengan hasil yang tidak terduga, hingga berperilaku selama penerjemahan atau pelaksanaan program dengan cara yang terdokumentasi dengan karakteristik lingkungan (dengan atau tanpa penerbitan pesan diagnostik), hingga penghentian terjemahan atau eksekusi (dengan penerbitan pesan diagnostik).
Singkatnya, perilaku yang tidak terdefinisi berarti segala sesuatu dapat terjadi mulai dari daemon yang terbang keluar dari hidung Anda hingga pacar Anda hamil.
Apa hubungan antara Perilaku Tidak Ditentukan dan Poin Urutan?
Sebelum saya membahasnya, Anda harus mengetahui perbedaan antara Perilaku Tidak Terdefinisi, Perilaku Tidak Ditentukan, dan Perilaku yang Didefinisikan Implementasi .
Anda juga harus tahu itu the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified
.
Sebagai contoh:
int x = 5, y = 6;
int z = x++ + y++; //it is unspecified whether x++ or y++ will be evaluated first.
Contoh lain di sini .
Sekarang Standar dalam §5/4
kata
- 1) Antara titik urutan sebelumnya dan berikutnya objek skalar harus memiliki nilai tersimpan dimodifikasi paling banyak sekali dengan evaluasi suatu ekspresi.
Apa artinya?
Secara tidak resmi itu berarti bahwa antara dua titik urutan suatu variabel tidak boleh dimodifikasi lebih dari sekali. Dalam pernyataan ekspresi, next sequence point
biasanya di titik koma terminasi, dan previous sequence point
di akhir pernyataan sebelumnya. Ekspresi juga dapat mengandung perantara sequence points
.
Dari kalimat di atas, ekspresi berikut memunculkan Perilaku Tidak Terdefinisi:
i++ * ++i; // UB, i is modified more than once btw two SPs
i = ++i; // UB, same as above
++i = 2; // UB, same as above
i = ++i + 1; // UB, same as above
++++++i; // UB, parsed as (++(++(++i)))
i = (i, ++i, ++i); // UB, there's no SP between `++i` (right most) and assignment to `i` (`i` is modified more than once btw two SPs)
Tapi ekspresi berikut baik-baik saja:
i = (i, ++i, 1) + 1; // well defined (AFAIK)
i = (++i, i++, i); // well defined
int j = i;
j = (++i, i++, j*i); // well defined
- 2) Selanjutnya, nilai sebelumnya harus diakses hanya untuk menentukan nilai yang akan disimpan.
Apa artinya? Ini berarti jika suatu objek ditulis ke dalam ekspresi penuh, setiap dan semua akses ke sana dalam ekspresi yang sama harus secara langsung terlibat dalam perhitungan nilai yang akan ditulis .
Misalnya dalam i = i + 1
semua akses i
(dalam LHS dan dalam RHS) secara langsung terlibat dalam perhitungan nilai yang akan ditulis. Jadi tidak apa-apa.
Aturan ini secara efektif membatasi ekspresi hukum pada akses yang secara nyata mendahului modifikasi.
Contoh 1:
std::printf("%d %d", i,++i); // invokes Undefined Behaviour because of Rule no 2
Contoh 2:
a[i] = i++ // or a[++i] = i or a[i++] = ++i etc
tidak diizinkan karena salah satu akses i
(yang masuk a[i]
) tidak ada hubungannya dengan nilai yang akhirnya disimpan di i (yang terjadi berulang i++
), dan jadi tidak ada cara yang baik untuk mendefinisikan - baik untuk pemahaman kita atau compiler's - apakah akses harus dilakukan sebelum atau setelah nilai yang bertambah disimpan. Jadi perilakunya tidak terdefinisi.
Contoh 3:
int x = i + i++ ;// Similar to above
Tindak lanjut jawaban untuk C ++ 11 di sini .
*p++ = 4
bukan Perilaku Tidak Terdefinisi.*p++
diartikan sebagai*(p++)
.p++
mengembalikanp
(salinan) dan nilai yang tersimpan di alamat sebelumnya. Mengapa itu memohon pada UB? Tidak apa-apa.++i
dan yang ditugaskani
. Ekspresi kedua tidak memanggil UB karena ekspresii
tidak mengubah nilaii
. Dalam contoh keduai++
diikuti oleh titik urutan (,
) sebelum operator penugasan dipanggil.Ini adalah tindak lanjut dari jawaban saya sebelumnya dan berisi materi yang terkait dengan C ++ 11. .
Prasyarat : Pengetahuan dasar tentang Hubungan (Matematika).
Benarkah tidak ada Sequence Points di C ++ 11?
Iya! Ini sangat benar.
Sequence Points telah digantikan oleh Sequencing Before dan Sequenced After (dan Unafterenced dan Indeterminately Sequencing ) hubungan di C ++ 11.
Apa sebenarnya hal 'Diurutkan sebelum' ini?
Sequencing Before (§1.9 / 13) adalah relasi yang:
antara evaluasi yang dilakukan oleh utas tunggal dan menginduksi urutan parsial yang ketat 1
Secara formal itu berarti diberi dua evaluasi (Lihat di bawah)
A
danB
, jikaA
sudah diurutkan sebelumB
, maka eksekusiA
akan mendahului pelaksanaanB
. JikaA
tidak diurutkan sebelumB
danB
tidak diurutkan sebelumnyaA
, makaA
danB
tidak dilanjutkan 2 .Mengevaluasi
A
danB
secara tidak pasti diurutkan ketika salahA
diurutkan sebelumB
atauB
diurutkan sebelumnyaA
, tetapi tidak ditentukan yang mana 3 .[CATATAN]
1: Sebuah urutan parsial yang ketat adalah relasi biner
"<"
lebih satu setP
yangasymmetric
, dantransitive
, yaitu, untuk semuaa
,b
danc
diP
, kita mendapati bahwa:........ (i). jika a <b maka ¬ (b <a) (
asymmetry
);........ (ii). jika a <b dan b <c maka a <c (
transitivity
).2: Pelaksanaan evaluasi yang tidak dilakukan dapat tumpang tindih .
3: evaluasi yang diurutkan secara tidak ditentukan tidak dapat tumpang tindih , tetapi keduanya dapat dieksekusi terlebih dahulu.
Apa arti dari kata 'evaluasi' dalam konteks C ++ 11?
Dalam C ++ 11, evaluasi ekspresi (atau sub-ekspresi) secara umum meliputi:
perhitungan nilai (termasuk menentukan identitas suatu objek untuk evaluasi glvalue dan mengambil nilai yang sebelumnya ditugaskan ke objek untuk evaluasi prvalue ) dan
inisiasi efek samping .
Sekarang (§1.9 / 14) mengatakan:
Contoh sepele:
int x;
x = 10;
++x;
Perhitungan nilai dan efek samping yang terkait dengan
++x
diurutkan setelah perhitungan nilai dan efek samping darix = 10;
Jadi harus ada hubungan antara Perilaku Tidak Terdefinisi dan hal-hal yang disebutkan di atas, kan?
Iya! Baik.
Dalam (§1.9 / 15) telah disebutkan itu
Sebagai contoh :
+
operator tidak diprioritaskan satu sama lain.<<
dan>>
operator tidak dilakukan relatif terhadap satu sama lain.4: Dalam ekspresi yang dievaluasi lebih dari satu kali selama pelaksanaan suatu program, evaluasi subekspresi yang tidak ditentukan dan tidak ditentukan secara berurutan tidak perlu dilakukan secara konsisten dalam evaluasi yang berbeda.
Itu berarti dalam
x + y
perhitungan nilaix
dany
diurutkan sebelum perhitungan nilai(x + y)
.Lebih penting
Contoh:
i = i++ * ++i; // Undefined Behaviour
i = ++i + i++; // Undefined Behaviour
i = ++i + ++i; // Undefined Behaviour
i = v[i++]; // Undefined Behaviour
i = v[++i]: // Well-defined Behavior
i = i++ + 1; // Undefined Behaviour
i = ++i + 1; // Well-defined Behaviour
++++i; // Well-defined Behaviour
f(i = -1, i = -1); // Undefined Behaviour (see below)
Ekspresi
(5)
,(7)
dan(8)
jangan aktifkan perilaku yang tidak terdefinisi. Lihatlah jawaban berikut untuk penjelasan yang lebih rinci.Catatan Akhir :
Jika Anda menemukan kesalahan dalam pos silakan tinggalkan komentar. Pengguna yang kuat (Dengan rep> 20000) jangan ragu untuk mengedit posting untuk memperbaiki kesalahan ketik dan kesalahan lainnya.
sumber
f(i = -1, i = 1)
?++i
(nilai dievaluasi sebelum+
operator yang menggunakannya), standar masih tidak mengatakan bahwa efek sampingnya harus diselesaikan. Tetapi pada kenyataannya, karena mengembalikan ref kelvalue
yang itui
sendiri, itu HARUS menyelesaikan efek samping karena evaluasi harus selesai, oleh karena itu nilainya harus up to date. Sebenarnya ini adalah bagian yang gila.C ++ 17 (
N4659
) termasuk proposal Refining Expression Evaluation Order untuk Idiomatic C ++ yang mendefinisikan urutan yang lebih ketat dari evaluasi ekspresi.Secara khusus, kalimat berikut
bersama dengan klarifikasi berikut
membuat beberapa kasus perilaku yang sebelumnya tidak terdefinisi valid, termasuk yang dipertanyakan:
Namun beberapa kasus serupa lainnya masih mengarah pada perilaku yang tidak terdefinisi.
Dalam
N4140
:Tapi di
N4659
Tentu saja, menggunakan kompiler yang memenuhi syarat C ++ 17 tidak harus berarti seseorang harus mulai menulis ekspresi seperti itu.
sumber
i = i++ + 1;
perilaku didefinisikan dalam c ++ 17, saya pikir bahkan jika "operan yang tepat diurutkan sebelum operan kiri", namun modifikasi untuk "i ++" dan efek samping untuk penugasan tidak dilanjutkan, tolong berikan rincian lebih lanjut untuk menafsirkan iniSaya menduga ada alasan mendasar untuk perubahan itu, bukan sekadar kosmetik untuk membuat interpretasi yang lama menjadi lebih jelas: alasan itu adalah konkurensi. Urutan elaborasi yang tidak ditentukan hanyalah pemilihan salah satu dari beberapa urutan serial yang mungkin, ini sangat berbeda dengan sebelum dan setelah pemesanan, karena jika tidak ada pemesanan yang ditentukan, evaluasi bersamaan dimungkinkan: tidak demikian halnya dengan aturan lama. Misalnya di:
sebelumnya a maka b, atau, b lalu a. Sekarang, a dan b dapat dievaluasi dengan instruksi yang disisipkan atau bahkan pada core yang berbeda.
sumber
Di
C99(ISO/IEC 9899:TC3)
mana tampaknya absen dari diskusi ini sejauh ini steteents berikut dibuat mengenai urutan evaluasi.sumber