【问题标题】:Difference between perror() and printf()perror() 和 printf() 的区别
【发布时间】:2015-12-05 09:00:23
【问题描述】:

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

【问题讨论】:

标签: c linux stdout stderr


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      除了其他答案之外,您还可以在stderrerrno(3) 上使用fprintf(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)),你最好使用系统日志(即调用openlog(3)之后调用daemon),因为daemon可以重定向stderr 到/dev/null

      【讨论】:

        【解决方案4】:

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

        对于错误消息和诊断,使用stderr,在stderr上打印 使用了错误。 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 是空指针,则只会打印消息。其他的会被忽略

        要了解更多您也可以参考The complete reference C的第332页

        【讨论】:

          【解决方案5】:

          使用 perror() 的一大优势:

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

          【讨论】:

            【解决方案6】:

            错误

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

            printf

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

            【讨论】:

            • "该函数的一般用途是由于错误而停止执行过程。"。 perror()根本没有停止程序。
            • 呃,请问你的措辞是什么意思?
            • @alk 它通常用于停止进程,例如perror(errno);exit(1);
            • 好吧,那么 perror 不用于停止进程。在您的示例中,它与停止进程一起使用。 Thoug,我不确定我会说它通常仅在这种情况下使用。所以请不要将 perror 与停止进程混为一谈。
            猜你喜欢
            • 2014-01-31
            • 1970-01-01
            • 2011-06-05
            • 2015-01-20
            • 2015-10-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多