GNU/Linux >> Belajar Linux >  >> Linux

Mengapa fclose(NULL) glibc menyebabkan kesalahan segmentasi alih-alih mengembalikan kesalahan?

fclose membutuhkan sebagai argumennya FILE pointer diperoleh dengan fopen , salah satu aliran standar stdin , stdout , atau stderr , atau dengan cara lain yang ditentukan oleh implementasi. Penunjuk nol bukan salah satunya, jadi perilakunya tidak terdefinisi, seperti halnya fclose((FILE *)0xdeadbeef) akan menjadi. NULL tidak spesial di C; selain dari fakta bahwa itu dijamin untuk membandingkan tidak sama dengan pointer yang valid, itu seperti pointer tidak valid lainnya, dan menggunakannya memunculkan perilaku yang tidak terdefinisi kecuali ketika antarmuka Anda meneruskannya ke dokumen sebagai bagian dari kontraknya NULL memiliki beberapa arti khusus untuk itu.

Selanjutnya, kembali dengan kesalahan akan valid (karena perilaku tidak terdefinisi) tetapi perilaku berbahaya untuk implementasi, karena menyembunyikan perilaku tidak terdefinisi . Hasil yang lebih disukai dari penerapan perilaku yang tidak terdefinisi selalu berupa crash, karena menyoroti kesalahan dan memungkinkan Anda untuk memperbaikinya. Sebagian besar pengguna fclose jangan memeriksa nilai pengembalian kesalahan, dan saya berani bertaruh bahwa kebanyakan orang cukup bodoh untuk memberikan NULL ke fclose tidak akan cukup pintar untuk memeriksa nilai kembalian dari fclose . Argumen dapat dibuat bahwa orang harus periksa kembali nilai fclose secara umum, karena flush terakhir bisa gagal, tetapi ini tidak diperlukan untuk file yang dibuka hanya untuk dibaca, atau jika fflush dipanggil secara manual sebelum fclose (yang merupakan idiom yang lebih cerdas karena lebih mudah menangani kesalahan saat Anda masih membuka file).


fclose(NULL) harus berhasil. free(NULL) berhasil, karena memudahkan penulisan kode pembersihan.

Sayangnya, bukan itu yang didefinisikan. Oleh karena itu, Anda tidak dapat menggunakan fclose(NULL) dalam program portabel. (Misalnya, lihat http://pubs.opengroup.org/onlinepubs/9699919799/).

Seperti yang telah disebutkan orang lain, Anda biasanya tidak menginginkan kesalahan kembali jika Anda meneruskan NULL ke tempat yang salah. Anda menginginkan pesan peringatan, setidaknya pada build debug/tes. Dereferencing NULL memberi Anda pesan peringatan langsung, dan kesempatan untuk mengumpulkan backtrace yang mengidentifikasi kesalahan pemrograman :). Saat Anda memprogram, segfault adalah kesalahan terbaik yang bisa Anda dapatkan. C memiliki lebih banyak kesalahan halus, yang membutuhkan waktu lebih lama untuk di-debug...

Dimungkinkan untuk menyalahgunakan pengembalian kesalahan untuk meningkatkan ketahanan terhadap kesalahan pemrograman. Namun, jika Anda khawatir kerusakan perangkat lunak akan kehilangan data, perhatikan bahwa hal yang persis sama dapat terjadi, mis. jika perangkat keras Anda kehilangan daya. Itu sebabnya kami memiliki penyimpanan otomatis (karena editor teks Unix dengan nama dua huruf seperti ex dan vi). Lebih baik perangkat lunak Anda mogok secara kasat mata, daripada melanjutkan dengan keadaan yang tidak konsisten.


Kesalahan yang dibicarakan halaman manual adalah kesalahan runtime, bukan kesalahan pemrograman. Anda tidak bisa hanya meneruskan NULL ke API apa pun yang mengharapkan penunjuk dan berharap API itu melakukan sesuatu yang masuk akal. Meneruskan NULL penunjuk ke fungsi yang didokumentasikan untuk meminta penunjuk ke data adalah bug.

Pertanyaan terkait:Baik di C atau C++, haruskah saya memeriksa parameter penunjuk terhadap NULL/nullptr?

Mengutip komentar R. pada salah satu jawaban atas pertanyaan itu:

... Anda sepertinya membingungkan kesalahan yang timbul dari kondisi luar biasa di lingkungan operasi (fs penuh, memori habis, jaringan mati, dll.) dengan kesalahan pemrograman. Dalam kasus sebelumnya, tentu saja program yang tangguh harus mampu menanganinya dengan baik. Yang terakhir, program yang tangguh tidak dapat mengalaminya sejak awal.


Linux
  1. Kesalahan C++:referensi tidak terdefinisi ke 'clock_gettime' dan 'clock_settime'

  2. Mengapa connect() memberikan EADDRNOTAVAIL?

  3. Cara termudah untuk menemukan Kesalahan Segmentasi

  1. Mengapa beberapa pemrogram kernel menggunakan goto alih-alih simple while loops?

  2. git add mengembalikan kesalahan fatal:di luar repositori

  3. Mengapa eval harus dihindari di Bash, dan apa yang harus saya gunakan?

  1. Gparted Error – Segmentation Fault (core Dumped)?

  2. Mengapa ENOENT berarti Tidak ada file atau direktori seperti itu?

  3. Kesalahan segmentasi saat Qt QApplication dibuat dengan yang baru