Kapan saya harus menggunakan perror (“…”) dan fprintf (stderr, “…”)?

105

Membaca halaman manual dan beberapa kode tidak benar-benar membantu saya dalam memahami perbedaan antara - atau lebih baik, kapan saya harus menggunakan - perror("...")atau fprintf(stderr, "...").

freeboy1015
sumber

Jawaban:

113

Memanggil perrorakan memberi Anda nilai yang diinterpretasikan errno, yang merupakan nilai kesalahan lokal-thread yang ditulis oleh sistem POSIX (yaitu, setiap thread memiliki nilainya sendiri untuk errno). Misalnya, jika Anda membuat panggilan ke open(), dan ada kesalahan yang dihasilkan (yaitu, kembali -1), Anda kemudian dapat memanggil perrorsegera setelah itu untuk melihat kesalahan yang sebenarnya. Perlu diingat bahwa jika Anda memanggil syscall lain untuk sementara, maka nilai di errnoakan ditimpa, dan panggilan perrortidak akan berguna dalam mendiagnosis masalah Anda jika kesalahan dihasilkan oleh syscall sebelumnya.

fprintf(stderr, ...)di sisi lain dapat digunakan untuk mencetak pesan kesalahan kustom Anda sendiri. Dengan mencetak ke stderr, Anda menghindari keluaran pelaporan kesalahan Anda tercampur dengan keluaran "normal" yang seharusnya menjadi stdout.

Perlu diingat bahwa fprintf(stderr, "%s\n", strerror(errno))ini mirip dengan perror(NULL)karena panggilan ke strerror(errno)akan menghasilkan nilai string yang dicetak untuk errno, dan Anda kemudian dapat menggabungkannya dengan pesan kesalahan khusus lainnya melalui fprintf.

Jason
sumber
3
oh, mengerti. Fungsi perror bekerja secara berbeda tergantung pada nilai errno. If you use a function that effects errno then it makes sense to use perrorJika Anda menggunakan fungsi yang tidak mempengaruhi errno dan hanya mengembalikan kode kesalahan, Anda harus menggunakan fprintf (stderr, fmt, ...). Misalnya, strtol akan mengembalikan LONG_MAX atau LONG_MIN jika string di luar jangkauan dan menyetel errno ke ERANGE. Jadi jika strtol gagal karena di luar jangkauan, saya akan menggunakan perror.
freeboy1015
6
Satu detail, strerrortidak perlu thread-safe. Itu bodoh, tapi itulah standarnya. strerror_ldapat digunakan sebagai pengganti drop-in pada sistem POSIX 2008. strerror_rjuga tersedia pada sistem yang lebih lama tetapi memiliki masalah yang sangat buruk dengan beberapa sistem yang memiliki versi yang tidak sesuai.
R .. GitHub STOP HELPING ICE
juga sebagai nitpick, saya pikir perrormenambahkan '\n'di akhir sehingga formatnya akan menjadi "%s\n", bukan?
Jens Gustedt
1
@R .., ha, saya sudah punya, dan sejauh yang saya tahu mereka tidak membayar saya apa-apa. Dan karena MS tampaknya menghentikan dukungan mereka untuk C sepenuhnya, pada akhirnya saya akan menjadi satu-satunya :) strerror_ssebenarnya tidak terlalu buruk sebagai antarmuka.
Jens Gustedt
2
Memotong dukungan sepenuhnya? Sepertinya mereka membodohi panitia lagi. Memasukkan _ssampah mereka ke standar pada dasarnya adalah permainan oleh MS ("Jika Anda mengadopsi antarmuka kami, kami akan mempertimbangkan untuk benar-benar membuat produk kami mendukung standar Anda.") Dan tentu saja sekarang mereka tidak menindaklanjuti. Sebenarnya saya setuju kalau interface yang satu ini sendiri tidak jelek. Yang buruk adalah propaganda (dalam bentuk peringatan kompilator) bahwa sebagian besar pustaka standar "tidak aman" dan bahwa seluruh keluarga _sfungsi harus digunakan alih-alih yang standar.
R .. GitHub STOP HELPING ICE
40

Mereka melakukan hal-hal yang agak berbeda.

Anda gunakan perror()untuk mencetak pesan stderryang sesuai dengan errno. Anda gunakan fprintf()untuk mencetak apa pun ke stderr, atau aliran lainnya. perror()adalah fungsi pencetakan yang sangat terspesialisasi:

perror(str);

setara dengan

if (str)
    fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
    fprintf(stderr, "%s\n", strerror(errno));
freeboy1015
sumber
12

perror(const char *s): mencetak string yang Anda berikan diikuti dengan string yang menjelaskan nilai saat ini errno.

stderr: ini adalah aliran keluaran yang digunakan untuk menyalurkan pesan kesalahan Anda sendiri ke (default ke terminal).

Relevan:

char *strerror(int errnum): berikan nomor kesalahan, dan itu akan mengembalikan string kesalahan terkait.

Adib Saad
sumber
2

perror () selalu menulis ke stderr; strerr (), digunakan bersama dengan fprintf (), dapat menulis ke keluaran apa pun - termasuk stderr tetapi tidak secara eksklusif.

fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")

Lebih lanjut, perror menerapkan format teksnya sendiri "teks: deskripsi kesalahan"

Sebastien
sumber
-2

Fungsi perror membutuhkan lebih banyak waktu untuk melakukan panggilan eksekusi dari ruang pengguna ke ruang kernal sedangkan panggilan fprintf menuju api ke kernal

vivek singh
sumber