perror() 和 printf() 之间的区别
Difference between perror() and printf()
我读到 perror()
和 printf()
都写入终端屏幕。但是 perror()
写入 stderr
而 printf()
写入 stdout
。因此,要打印错误,为什么在 printf()
可以做到的情况下使用 perror()
。
因为可能存在您希望 stderr
打印到控制台但其他输出根本不打印的配置(例如,删除冗长)。在其他情况下,您可能需要重定向 stderr
以写入文件,这在您进行生产时很有用,并且该文件可用于了解您无法自行调试的远程计算机上出现的问题。
一般来说,您可以更好地控制控制台输出的处理方式,具体取决于它们的类型。
请参阅 this answer 了解如何在代码中进行流重定向。
或者,请参阅 this link,了解如何强制流重定向到文件或忽略已编译程序上的流(在 bash)
printf()
无法写入 stderr
。 fprintf()
可以。 perror()
总是这样。
不要求写入 stdout
或 stderr
写入终端屏幕 - 这取决于实现(因为并非所有系统甚至都有终端)。也没有要求写入 stdout
和 stderr
导致写入同一设备(例如,一个可以重定向到文件,而另一个重定向到管道)。
perror()
将使用错误代码含义的内置知识来实现,由静态 errno
表示,标准库中的各种函数使用它来报告错误情况。特定值的含义是实现定义的(即它们在编译器和库之间有所不同)。
错误
该函数的一般用途是由于错误而停止执行过程。 perror 产生的错误消息是平台相关的。您也可以打印自己的错误消息。
打印
该函数的一般用途是打印用户定义的消息并继续执行。
共有三个标准流stdin
stdout
stderr
。您可以 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 的冗长性使得只能访问错误可能会隐藏我们需要修复的错误。
我读到 perror()
和 printf()
都写入终端屏幕。但是 perror()
写入 stderr
而 printf()
写入 stdout
。因此,要打印错误,为什么在 printf()
可以做到的情况下使用 perror()
。
因为可能存在您希望 stderr
打印到控制台但其他输出根本不打印的配置(例如,删除冗长)。在其他情况下,您可能需要重定向 stderr
以写入文件,这在您进行生产时很有用,并且该文件可用于了解您无法自行调试的远程计算机上出现的问题。
一般来说,您可以更好地控制控制台输出的处理方式,具体取决于它们的类型。
请参阅 this answer 了解如何在代码中进行流重定向。
或者,请参阅 this link,了解如何强制流重定向到文件或忽略已编译程序上的流(在 bash)
printf()
无法写入 stderr
。 fprintf()
可以。 perror()
总是这样。
不要求写入 stdout
或 stderr
写入终端屏幕 - 这取决于实现(因为并非所有系统甚至都有终端)。也没有要求写入 stdout
和 stderr
导致写入同一设备(例如,一个可以重定向到文件,而另一个重定向到管道)。
perror()
将使用错误代码含义的内置知识来实现,由静态 errno
表示,标准库中的各种函数使用它来报告错误情况。特定值的含义是实现定义的(即它们在编译器和库之间有所不同)。
错误
该函数的一般用途是由于错误而停止执行过程。 perror 产生的错误消息是平台相关的。您也可以打印自己的错误消息。
打印
该函数的一般用途是打印用户定义的消息并继续执行。
共有三个标准流stdin
stdout
stderr
。您可以 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 的冗长性使得只能访问错误可能会隐藏我们需要修复的错误。