Когда мне следует использовать perror («…») и fprintf (stderr, «…»)?

105

Чтение страниц руководства и некоторого кода на самом деле не помогло мне понять разницу между - или, что лучше, когда мне следует использовать - perror("...")или fprintf(stderr, "...").

freeboy1015
источник

Ответы:

113

Вызов 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.

Джейсон
источник
3
О, понятно. Функция perror работает по-разному в зависимости от значения errno. 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.
freeboy1015,
6
Одна деталь, strerrorне обязательно быть поточно-ориентированной. Это глупо, но это стандарт. strerror_lможет использоваться вместо этого в качестве замены в системах POSIX 2008. strerror_rтакже доступен в старых системах, но имеет действительно неприятные проблемы с некоторыми системами, имеющими его несовместимые версии.
R .. GitHub НЕ ПОМОГАЕТ ICE
также в качестве придирки, думаю, perrorдобавляет '\n'в конце, так что формат будет "%s\n", нет?
Йенс Густедт,
1
@R .., ха, у меня уже есть, и, насколько я знаю, они мне ничего не платят. И поскольку MS, похоже, полностью урезает свою поддержку C, в конце концов, я буду единственным :) На strerror_sсамом деле это не так уж плохо как интерфейс.
Йенс Густедт,
2
Полностью отрезать опору? Похоже, они снова обманули комитет. Внесение их _sмусора в стандарт было в основном игрой MS («Если вы воспользуетесь нашими интерфейсами, мы рассмотрим, как сделать так, чтобы наши продукты поддерживали ваш стандарт»), и, конечно, теперь они не следуют этому. На самом деле я согласен, что этот интерфейс сам по себе неплох. Что плохо, так это пропаганда (в виде предупреждений компилятора) о том, что большая часть стандартной библиотеки «небезопасна» и что все семейство _sфункций должно использоваться вместо стандартных.
R .. GitHub НЕ ПОМОГАЕТ ICE
40

Они делают разные вещи.

Вы используете 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));
freeboy1015
источник
12

perror(const char *s): печатает переданную вами строку, за которой следует строка, описывающая текущее значение errno.

stderr: это выходной поток, используемый для передачи ваших собственных сообщений об ошибках (по умолчанию на терминал).

Соответствующий:

char *strerror(int errnum): присвойте ему номер ошибки, и он вернет соответствующую строку ошибки.

Адиб Саад
источник
2

perror () всегда пишет в stderr; strerr (), используемый вместе с fprintf (), может писать в любой вывод, включая stderr, но не исключительно.

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

Кроме того, perror накладывает свой собственный текст в формате «текст: описание ошибки».

Себастьян
источник
-2

Функция Perror требует больше времени для выполнения, вызов переходит из пользовательского пространства в пространство ядра, тогда как вызовы fprintf отправляются с api на ядро

Вивек Сингх
источник