Perilaku tidak terdefinisi menyerang ketika program akan menyebabkan perilaku tak terdefinisi apa pun yang terjadi selanjutnya. Namun, Anda memberi contoh berikut.
int num = ReadNumberFromConsole();
if (num == 3) {
PrintToConsole(num);
*((char*)NULL) = 0;
}
Kecuali jika kompilator mengetahui definisinya PrintToConsole
, ia tidak dapat menghapus if (num == 3)
kondisional. Anggaplah Anda memiliki LongAndCamelCaseStdio.h
header sistem dengan deklarasi berikut ini PrintToConsole
.
void PrintToConsole(int);
Tidak terlalu membantu, oke. Sekarang, mari kita lihat seberapa jahat (atau mungkin tidak begitu jahat, perilaku tidak terdefinisi bisa lebih buruk) vendor, dengan memeriksa definisi sebenarnya dari fungsi ini.
int printf(const char *, ...);
void exit(int);
void PrintToConsole(int num) {
printf("%d\n", num);
exit(0);
}
Kompilator sebenarnya harus berasumsi bahwa sembarang fungsi yang tidak diketahui oleh kompilator dapat keluar atau memunculkan pengecualian (dalam kasus C ++). Anda dapat melihat bahwa *((char*)NULL) = 0;
tidak akan dieksekusi, karena eksekusi tidak akan dilanjutkan setelah PrintToConsole
panggilan.
Perilaku tidak terdefinisi menyerang kapan PrintToConsole
benar-benar kembali. Kompilator mengharapkan ini tidak terjadi (karena ini akan menyebabkan program mengeksekusi perilaku tidak terdefinisi apapun yang terjadi), oleh karena itu apapun bisa terjadi.
Namun, mari pertimbangkan hal lain. Katakanlah kita melakukan pemeriksaan null, dan menggunakan variabel setelah pemeriksaan null.
int putchar(int);
const char *warning;
void lol_null_check(const char *pointer) {
if (!pointer) {
warning = "pointer is null";
}
putchar(*pointer);
}
Dalam hal ini, mudah untuk diperhatikan bahwa lol_null_check
membutuhkan pointer non-NULL. Menetapkan ke warning
variabel non-volatile global bukanlah sesuatu yang dapat keluar dari program atau memunculkan pengecualian apa pun. Ini pointer
juga non-volatile, sehingga tidak dapat secara ajaib mengubah nilainya di tengah fungsi (jika ya, itu adalah perilaku yang tidak ditentukan). Panggilanlol_null_check(NULL)
akan menyebabkan perilaku tidak terdefinisi yang dapat menyebabkan variabel tidak ditetapkan (karena pada titik ini, fakta bahwa program mengeksekusi perilaku tidak terdefinisi diketahui).
Namun, perilaku tidak terdefinisi berarti program dapat melakukan apa saja. Oleh karena itu, tidak ada yang menghentikan perilaku tidak terdefinisi dari kembali ke masa lalu, dan menghentikan program Anda sebelum baris pertama int main()
eksekusi. Ini adalah perilaku yang tidak jelas, tidak harus masuk akal. Mungkin juga macet setelah mengetik 3, tetapi perilaku yang tidak ditentukan akan kembali ke masa lalu, dan macet bahkan sebelum Anda mengetik 3. Dan siapa tahu, mungkin perilaku yang tidak ditentukan akan menimpa RAM sistem Anda, dan menyebabkan sistem Anda macet 2 minggu kemudian, sementara program Anda yang tidak ditentukan tidak berjalan.