【问题标题】:Can I ever assume that a C stdlib function doesn't use errno?我可以假设 C stdlib 函数不使用 errno 吗?
【发布时间】:2010-12-08 18:43:21
【问题描述】:

我正在看一段 C 代码,它类似于

void printerror(char *message)
{
    printf ("There was an error: '%s'\n", message);
    switch (errno) {
       ... do stuff depending on errno
    }
}

我认为这可能是个问题,因为 printf 可能会在进入函数和到达 switch 之间更改 errno。但是,printf 的手册页没有说明它设置 errno,所以我可以假设它永远不会设置它吗?标准中有什么东西可以保证哪些函数会使用errno,哪些函数不会使用errno?

【问题讨论】:

  • 为什么不做类似int saved_error = errno 的事情?
  • @Thanatos:很明显。问题是对于所有 stdlib 函数是否真的有必要(答案表明确实如此)

标签: c errno


【解决方案1】:

任何函数都可以设置 errno,但前提是它设置为非零值。 ANSI C 规范指出:

errno 的值在程序启动时为零,但从不设置为 任何库函数为零。* errno 的值可以设置为 库函数调用的非零值,无论是否有错误, 前提是 errno 的使用没有记录在 标准中的功能。

*因此,使用 errno 进行错误检查的程序应该设置它 在库函数调用之前归零,然后在调用之前检查它 后续库函数调用。

因此,如果您使用 errno,最佳实践方法是在可能会失败的库调用之前立即将该值设置为 0,然后立即读取它。在上述情况下,添加如下内容就足够了:

int localErrno = errno

在 printf 语句之前并使用 localErrno 进行切换。当然,这假设在失败的函数和您对 printerror 的调用之间没有库调用。如果有,您需要在调用失败后存储 errno 并将其传递给您的 printerror 函数。

【讨论】:

    【解决方案2】:

    在极少数情况下,printf 可以设置 errno。如果您将程序中的标准输出重定向到文件并且文件系统已满,printf() 将返回一个负数并将 errno 设置为 ENOSPC(设备上没有剩余空间)。您应该在调用 printf() 之前制作 errno 的本地副本。

    【讨论】:

      【解决方案3】:

      C99 标准规定了以下内容:

      errno 的值在程序启动时为零,但绝不会被任何库函数设置为零。 errno 的值可以通过库函数调用设置为非零值,无论是否存在错误,只要在本国际标准的函数描述中没有记录 errno 的使用。

      所以,简而言之,errno 可以由 any 库函数设置。为了确定它是否确实在给定的情况下,标准做法是在调用相关函数之前将其设置为零。

      【讨论】:

      • 一种更有效的标准做法是永远不要检查errno,除非相关函数返回指示错误的值。不断将errno 设置为零可能会产生一点成本,而实际收益很少或没有。当然,这整个问题与 OP 的问题有些正交。
      • 公平点。不过,有些库函数很难区分实际的错误返回值和良性的返回值。
      猜你喜欢
      • 2015-05-05
      • 2018-07-17
      • 1970-01-01
      • 1970-01-01
      • 2021-05-02
      • 2016-04-22
      • 2021-02-16
      • 2022-09-30
      • 1970-01-01
      相关资源
      最近更新 更多