Читання чоловічих сторінок та якогось коду насправді не допомогло мені зрозуміти різницю між тим, чи краще, коли я повинен використовувати - perror("...")
чи fprintf(stderr, "...")
.
Читання чоловічих сторінок та якогось коду насправді не допомогло мені зрозуміти різницю між тим, чи краще, коли я повинен використовувати - perror("...")
чи fprintf(stderr, "...")
.
Відповіді:
Виклик perror
дасть вам інтерпретоване значення errno
, яке є локальним значенням помилки потоку, записаним через POSIX-систематичні дзвінки (тобто кожен потік має своє значення для errno
). Наприклад, якщо ви здійснили дзвінок open()
, і виникла помилка (тобто вона повернулася -1
), ви зможете зателефонувати perror
одразу після цього, щоб побачити, що таке фактична помилка. Майте на увазі, що якщо ви тим часом зателефонуєте на інші системні дзвінки, то значення в errno
ньому буде записано, і виклик perror
не буде корисним для діагностики вашої проблеми, якщо помилка була викликана попередньою системою виклику.
fprintf(stderr, ...)
з іншого боку, можна використовувати для друку власних повідомлень про помилки. Друкуючи на stderr
, ви уникаєте змішування результатів звітування про помилки з "нормальним" висновком, до якого слід працювати stdout
.
Майте на увазі, що fprintf(stderr, "%s\n", strerror(errno))
це аналогічно perror(NULL)
тому, що при виклику до strerror(errno)
генеруватиметься надрукований рядок errno
, а потім ви можете комбінувати це з будь-яким іншим користувацьким повідомленням про помилку через fprintf
.
strerror
щоб не бути безпечним для потоків , не вимагається. Це дурно, але це стандарт. strerror_l
може використовуватись замість цього як заміна, що випадає, на системах POSIX 2008. strerror_r
також доступний для старих систем, але в деяких системах, що мають невідповідні версії, виникають неприємні проблеми.
perror
додає '\n'
наприкінці, щоб формат був "%s\n"
, ні?
strerror_s
насправді не так вже й погано, як інтерфейс.
_s
сміття в стандарт в основному було грою MS ("Якщо ви приймете наші інтерфейси, ми розглянемо, як насправді зробити так, щоб наші продукти підтримували ваш стандарт"), і, звичайно, зараз вони не дотримуються. Насправді я згоден, що цей один інтерфейс сам по собі не поганий. Що погано, це пропаганда (у вигляді попереджень компілятора) про те, що більшість стандартних бібліотек є "небезпечними" і що все сімейство _s
функцій слід використовувати замість стандартних.
Вони роблять досить різні речі.
Ви можете використовувати perror()
для друку повідомлень для того, stderr
що відповідає errno
. Ви використовуєте fprintf()
для друку будь- що stderr
або будь-який інший потік. perror()
є дуже спеціалізованою функцією друку:
perror(str);
еквівалентно
if (str)
fprintf(stderr, "%s: %s\n", str, strerror(errno));
else
fprintf(stderr, "%s\n", strerror(errno));
perror(const char *s)
: друкує рядок, який ви надаєте йому, а потім рядок, що описує поточне значення errno
.
stderr
: це вихідний потік, який використовується для передачі ваших власних повідомлень про помилки (за замовчуванням до терміналу).
Відповідне:
char *strerror(int errnum)
: дайте йому номер помилки, і він поверне пов'язаний рядок помилки.
perror () завжди пише в stderr; strerr (), який використовується разом з fprintf (), може записувати на будь-який вихід - включаючи stderr, але не виключно.
fprintf(stdout, "Error: %s", strerror(errno));
fprintf(stderr, "Error: %s", strerror(errno)); // which is equivalent to perror("Error")
Крім того, перор нав'язує свій власний текст "текст: опис помилки"
Функція Perror займає більше часу для виконання виклику, йде від простору користувача до простору ядра, коли виклики fprintf переходять до api до ядра
If you use a function that effects errno then it makes sense to use perror
. Якщо ви використовуєте функцію, яка не впливає на errno і просто повертає код помилки, ви повинні використовувати fprintf (stderr, fmt, ...). Наприклад, strtol поверне LONG_MAX або LONG_MIN, якщо рядок знаходиться поза діапазоном і встановить errno на ERANGE. Тож якщо strtol виходить з ладу через поза діапазон, я б застосував perror.