perror()和printf()的区别

6
我读到过perror()printf()都可以将内容输出到终端屏幕。但是perror()会输出到stderr,而printf()则会输出到stdout。那么,既然printf()也能输出错误信息,为什么还需要用perror()呢?

2
https://dev59.com/xXA75IYBdhLWcg3wRWyc - ashiquzzaman33
6个回答

7

printf()无法将内容写入stderr,而fprintf()可以,perror()总是会这样做。

要求将内容写入stdoutstderr,并不意味着一定要将其写入终端屏幕 - 这取决于实现方式(因为并非所有系统都有终端)。同时,将内容写入stdoutstderr也不意味着结果会被写入同一个设备(例如其中一个可能被重定向到文件,而另一个被重定向到管道)。

perror()将使用内置知识来实现对错误代码的解释,这些错误代码由静态变量errno表示,多个标准库函数用它来报告错误条件。特定值的含义是由实现定义的(即它们在编译器和库之间有所不同)。


2
除了其他答案之外,您可以在stderr上使用fprintf(3)errno(3)strerror(3)一起使用。
 fprintf(stderr, "something wrong: %s\n", strerror(errno));

在GNU libc系统(许多Linux系统)上,您可以使用%m转换说明符代替:
fprintf(stderr, "something wrong: %m\n");

您应该将错误消息输出到stderr(参见stderr(3));使用系统日志,可以参考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(3)),则最好使用系统日志(即在调用daemon之后调用openlog(3)),因为daemon可以将stderr重定向到/dev/null

2
因为有一些配置需要将stderr打印到控制台,但不希望其他输出被打印出来(例如,为了减少冗余)。在其他情况下,您可能需要重定向stderr以写入文件,这在生产环境中非常有用,因为该文件可以用于了解无法自行调试的远程计算机上发生了什么问题。
总的来说,您可以根据输出类型更好地控制如何处理控制台输出。
请参见此答案以了解如何在代码中进行流重定向。
或者,请参见此链接,了解如何强制将流重定向到文件或忽略已编译程序上的流(在bash中调用它)。

1

有三个标准流 stdin stdout stderr。您可以参考以了解不同流的重要性。

对于错误消息和诊断,使用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 参数、冒号、空格、关于当前 errno 错误代码的简短错误消息和换行符。

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

为了更好地理解,您还可以参考《C语言程序设计》大全第332页。


1

perror()的一个重要优点:

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


-3

perror

该函数的通用目的是由于错误而停止执行过程。 perror 产生的错误消息取决于平台。您也可以打印自己的错误消息。

printf

该函数的通用目的是打印用户定义的消息并继续执行。


4
该函数的一般目的是由于错误而停止执行过程。perror()根本不会停止程序。 - alk
那么,请问您的措辞意图是什么? - alk
1
@alk 通常用于停止进程,例如:perror(errno);exit(1); - Vineet1982
2
那么,perror并不用于停止进程。在您的示例中,它与停止进程一起使用。虽然我不确定是否可以说它通常仅在该情况下使用。因此,请不要将perror与停止进程混淆。 - Anders

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接