【问题标题】:Is there a reason why perror isn't widely seen in code for error handling? [closed]为什么 perror 在错误处理代码中没有被广泛看到是有原因的? [关闭]
【发布时间】:2013-01-07 04:44:59
【问题描述】:

查看 stackoverflow 或其他地方的代码,我似乎很少看到 perror() 用于报告错误的确切性质。 printf 更为常见。这是否表明 perror 有问题或缺失?鉴于它提供了更好的信息,我希望它会被更频繁地使用。

【问题讨论】:

  • 比什么更好的信息?在 C++ 中,您可能会使用异常,而使用 perror 只会打印愚蠢的“错误:成功”。
  • 它将打印 fopen、malloc 等的确切错误。也许我应该严格保留这个问题。
  • 花很多时间编写 Windows 应用程序?
  • 因为在许多较小的嵌入式系统中,不包括支持perror 的设施。您的代码是否向perror 提供信息?
  • 我很确定 perror() 与任何其他打印功能一样可能成功 - 它不应该分配内存。显然,如果没有 stderr,那么您就无法通知用户它出错了。但这听起来像是一个没有标准 I/O 的嵌入式系统,在这一点上,所有关于处理错误的赌注都落空了。 C 作为一种语言当然还在嵌入式中使用,但你可能根本没有“printf”和“perror”类型的函数。

标签: c++ c error-handling


【解决方案1】:

perror() 不会准确地为您提供发生错误的行号,而您的 printf() 将帮助您识别正在打印的确切行。所以我认为它对调试更有帮助,我所知道的 perror() 没有错......

【讨论】:

    【解决方案2】:

    我个人更喜欢strerror(),它做的事情大致相同,但允许您将错误消息与 printf 或类似函数一起使用,从而为程序的编码人员或用户提供更多有用,具体取决于程序的类型错误]。

    例如:

    errno = 0;
    FILE *f = fopen(argv[1], "rb");
    if (!f)
    {
        fprintf(stderr, "File %s open failed: error code %d ('%s')\n", 
                argv[1], errno, strerror(errno));
        exit(1);
    }
    

    这样,我们也知道哪个文件(假设它是一个复制文件的程序,perror 不一定会告诉你它是“源”还是“目标”)。

    如果错误是由于编程错误[或“预计不会出错的东西”],您还可以执行以下操作:

    #define UNEXPECTED(cond) do { if (cond) { do_unexpected(errno, #cond, __FILE__, __LINE__); } while(0)
    
    void do_unexpected(int err, const char* cond, const char *file, int line)
    {
        fprintf(stderr, "Unexpected error %s [errno=%d, errstr=%s] at %s:%d", 
                cond, err, strerror(errno), file, line);
        exit(1);
    }
    
    errno = 0;
    FILE *config = fopen("config.txt", "r");
    
    UNEXPECTED(!config); 
    
    ... 
    

    假设您不希望删除“config.txt”,例如 [这通常是非常糟糕的编程,但也许有一个正当的理由......]

    【讨论】:

    • 在调用fopen之前不要忘记将errno设置为0。
    • 虽然这是一件有用的事情,但我相信如果 fopen 失败它不会被“取消设置”,所以在上述情况下它并不是真正需要的。执行“if (errno != 0)”的代码绝对应该 [但无论如何这是相当糟糕的编码实践,因为 errno 可以由许多系统函数设置 - 你真的应该使用其他方法来确定是否出现问题]
    • 是的,你是对的;只有当您使用该值来检测错误时,您必须事先设置它。
    【解决方案3】:

    如果您在进行标准库调用之前将errno 设置为零并且该调用失败并且它是使用errno 描述失败原因的调用之一,那么perrorstrerror 可能会提供有用的解释。大多数人不关注errno,更不用说如何正确使用它了。这是更简单时代的产物。

    【讨论】:

      【解决方案4】:

      由于我使用的是 C++,所以我不使用 printf() 和 co,并且经常在启动时调用 sync_with_stdio(false)。此外,该功能的问题在于它只允许在本地打印错误。我经常遇到的是这样的:

      // setting errno
      if(!foo1(bar))
          throw_errno_exception("foo1");
      
      // returning errorcode
      if(int e = foo2(bar))
          throw_exception(e, "foo2");
      

      首先,不是每个函数都使用 errno。特别是对于新代码,我也不会这样做,而只是返回 int 并带有相应的错误代码。因此,对于那些“新”功能,我必须在使用 perror() 之前手动设置 errno。但是,我也不希望这样,因为失败的函数和我捕获'n'记录异常的地方之间通常有很大的差距。

      现在,在 C 中,您无法像在 C++ 异常中那样将附加信息传递到堆栈中。因此,在 C 中记录实际失败的函数以及失败位置的任何上下文更为重要。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-09
        • 1970-01-01
        • 2011-06-03
        • 1970-01-01
        • 2022-01-25
        • 1970-01-01
        • 2018-09-10
        • 1970-01-01
        相关资源
        最近更新 更多