perror() 和 printf() 之间的区别

Difference between perror() and printf()

我读到 perror()printf() 都写入终端屏幕。但是 perror() 写入 stderrprintf() 写入 stdout。因此,要打印错误,为什么在 printf() 可以做到的情况下使用 perror()

因为可能存在您希望 stderr 打印到控制台但其他输出根本不打印的配置(例如,删除冗长)。在其他情况下,您可能需要重定向 stderr 以写入文件,这在您进行生产时很有用,并且该文件可用于了解您无法自行调试的远程计算机上出现的问题。

一般来说,您可以更好地控制控制台输出的处理方式,具体取决于它们的类型。

请参阅 this answer 了解如何在代码中进行流重定向。

或者,请参阅 this link,了解如何强制流重定向到文件或忽略已编译程序上的流(在 bash)

printf() 无法写入 stderrfprintf()可以。 perror() 总是这样。

不要求写入 stdoutstderr 写入终端屏幕 - 这取决于实现(因为并非所有系统甚至都有终端)。也没有要求写入 stdoutstderr 导致写入同一设备(例如,一个可以重定向到文件,而另一个重定向到管道)。

perror() 将使用错误代码含义的内置知识来实现​​,由静态 errno 表示,标准库中的各种函数使用它来报告错误情况。特定值的含义是实现定义的(即它们在编译器和库之间有所不同)。

错误

该函数的一般用途是由于错误而停止执行过程。 perror 产生的错误消息是平台相关的。您也可以打印自己的错误消息。

打印

该函数的一般用途是打印用户定义的消息并继续执行。

共有三个标准流stdinstdoutstderr。您可以 refer 了解不同流的重要内容。

对于错误消息和诊断,使用 stderr,在 stderr 上打印 使用 Perror。 printf 不能那样做。 Perror 也用于处理来自系统调用的错误

fd = open (pathname, flags, mode);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}

你可以参考书上的更多内容The linux programming interface

void perror(const char *s)

Perror 按以下顺序打印消息:

s 的参数,一个冒号,一个 space ,一条有关错误的短消息,其错误代码当前在 errno 和换行符

在标准 C 中,如果 s 是空指针,则只会打印消息。其他事情将被忽略

要了解更多信息,您还可以参考 The complete reference C

的第 332 页

除了其他答案,您还可以使用 fprintf(3) on stderr and errno(3) with strerror(3) like

 fprintf(stderr, "something wrong: %s\n", strerror(errno));

在 GNU libc 系统(许多 Linux 系统)上,您可以改用 %m 转换说明符:

fprintf(stderr, "something wrong: %m\n");

您通常应该将错误消息输出到 stderr(请参阅 stderr(3)); see also syslog(3) 以使用系统日志记录。

不要忘记以 \n 结束格式字符串,因为 stderr 通常是行缓冲的(但有时不是)或者使用 fflush(3)

例如,您可能希望在 fopen 失败时同时显示错误、文件名和当前目录:

char* filename = somefilepath();
assert (filename != NULL);
FILE* f = fopen(filename, "r");
if (!f) {
   int e = errno; // keep errno, it could be later overwritten
   if (filename[0] == '/') /// absolute path
      fprintf(stderr, "failed to open %s : %s\n", filename, strerror(e));
   else { // we also try to show the current directory since relative path
      char dirbuf[128];
      memset (dirbuf, 0, sizeof(dirbuf));
      if (getcwd(dirbuf, sizeof(dirbuf)-1)) 
         fprintf(stderr, "failed to open %s in %s : %s\n", 
                 filename, dirbuf, sterror(e));
      else // unlikely case when getcwd failed so errno overwritten
         fprintf(stderr, "failed to open %s here : %s\n", 
                 filename, sterror(e));
   };
   exit(EXIT_FAILURE); // in all cases when fopen failed
 }

请记住,errno 可能会被多次失败覆盖(因此我们将其存储在 e 中,以防 getcwd 失败并覆盖 errno 的可能性很小)。

如果您的程序是守护程序(例如,在 调用 daemon 之后调用了 daemon(3)) you'll better use system log (i.e. call openlog(3) ),因为 daemon 可以重定向 stderr/dev/null

使用 perror() 的一大优势:

有时将 stdout 重定向到 /dev/null 非常有用,因为 stdout 的冗长性使得只能访问错误可能会隐藏我们需要修复的错误。