6

什么样的库函数面临什么样的错误会影响errno并将其设置为非零值?在我的以下程序中,我打算if(errno!=0)用作检查我使用的库函数是否正常运行的条件,这就是我发现的(见下面的代码):

首先,我曾经if(errno!=0)测试文件是否已成功打开fopen()。如果我尝试打开一个不存在的文件,则errno设置为非零(在我的情况下为 2),并通过打印errno每个阶段的值来验证。但是,如果我打开一个现有文件,则 errno 的值将保持为零,因为fopen()可以正确打开该文件。在这件事上,if(errno!=0)作为if(pFile==NULL)我已经注释掉的完美替代品。

如果文件被成功打开,errno仍然0,控制移动到第一个else块。这是我对errno. 在这里,由于我以r(read)模式打开文件并尝试使用 写入文件,因此fputc()我希望生成的写入错误设置errno为非零,就像fopen()它无法成功打开文件时设置的那样. 但是errno即使在使用fputc(). errno(这可以通过打印错误写入后的值来验证)。

为什么会这样?为什么一个函数面临的 I/O 错误fopen()设置errno其他函数面临的 while write 错误fputc()不影响errno?如果是这样,我们如何可靠地errno用作错误指标?我是否使用 errno 来测试 fopen() 是否成功运行,而不是“if(pFile==NULL)”不明智?我将感谢您对此的分析回答。

#include <stdio.h>
#include <errno.h>

int main ()
{

  FILE * pFile;
  printf("%d\n",errno);

  pFile = fopen("D:\\decrypt.txt","r");
  printf("%d\n",errno); // Prints 0 if fopen() successful,else 2

  //if(pFile==NULL) perror("Error opening file"); 

   if (errno!=0) perror ("Error opening file");

  else
  {
    fputc ('x',pFile);
     printf("%d\n",errno); //errno shows 0 even after write error

     //if (ferror (pFile))
    if (errno!=0)  //Condition evaluates false even if faulty write
      {
      printf ("Error Writing to decrypt.txt\n"); 
        }
    fclose (pFile);

  }
  return 0; 
}
4

3 回答 3

9

该文档主要告诉您哪个函数可以设置 中的哪些值errno,但是您需要了解一些规则:

  1. 没有库函数设置errno为零。
  2. errno仅当函数指示发生错误(并且函数记录为 set errno)时测试才有效。

第一点意味着如果你想知道,例如,你是否从 中得到了一个错误,你必须在调用它之前strtol()设置为 0。errno

第二点很关键;例如,在 Solaris 上,当通道不是终端时,经过多次 I/O 操作后,设置errno将是ENOTTY(不是终端)。没有错误;什么都没有失败;但是仅基于您的后续操作errno(而不是基于 I/O 操作报告的状态)会导致您认为一切都失败了。

因此,在您的代码中,fopen()调用可能会保留errno为非零值,即使它成功创建了文件流。你必须使用:

const char filename[] = "D:\\crypt.txt";
if ((pFile = fopen(filename, "r")) == 0)
{
    fprintf(stderr, "Failed to open %s for reading (%d: %s)\n",
            filename, errno, strerror(errno));
    ...return or exit...
}

注意:如果您需要调用一个可以改变的函数,请errno尽早捕获该值:

    int errnum = errno;
    fprintf(stderr, "Failed to open %s for reading (%d: %s)\n",
            filename, errnum, strerror(errnum));

永远不要宣布errno自己;总是#include <errno.h>用来做的。

我不清楚为什么您的代码在fputc()调用时没有出错。在我的 Mac OS X 10.8.3 系统上,等效代码失败并errno设置为 9 (EBADF) 'Bad file descriptor'。


这是在哪里记录的?它在 C 标准中,并由 POSIX 标准加强。

ISO/IEC 9899:2011 §7.5 错误<errno.h>

¶3errno初始线程中的值在程序启动时为零(errno其他线程中的初始值为不确定值),但任何库函数都不会将其设置为零。202)errno无论是否存在错误,库函数调用都可以将的值设置为非零,前提errno是本国际标准的函数描述中没有记录 的使用。

202)因此,errno用于错误检查的程序应在调用库函数之前将其设置为零,然后在随后的库函数调用之前对其进行检查。当然,库函数可以保存errnoon entry 的值,然后将其设置为零,只要errno在返回之前如果 ' 的值仍然为零,则恢复原始值。

以前版本的 C 标准中的措辞没有提到线程,但在其他方面是相似的。

请注意,fopen()C 标准中的描述没有提到errno. 因此,允许errno由 C 标准设定。相比之下,该mbsrtowcs()函数被记录为设置errno为 EILSEQ;它可能无法将其设置为其他值,因为 C 标准说它不应该(尽管如果它在某些条件下有更好的错误,则没有什么可以阻止实现这样做)。

POSIX 2008

POSIX 页面errno说:

许多函数在 中提供了一个错误号errno,它具有类型int并在 中定义<errno.h>。的值errno应仅在调用明确声明为其设置的函数之后定义,直到它被下一个函数调用更改或应用程序为其分配值。只有当函数的返回值errno表明它是有效的时,才应该检查它的值。应用程序应errno通过包含<errno.h>. 本卷 POSIX.1-2008 中的任何函数均不得设置errno为 0。errno成功调用函数后的设置未指定,除非该函数的描述指定errno不得修改。

未指定errno是使用外部链接声明的宏还是标识符。如果为了访问实际对象而禁止宏定义,或者程序定义了名称为 的标识符errno,则行为未定义。

存储在 errno 中的符号值记录在所有相关页面的 ERRORS 部分中。

以前版本的措辞类似。

于 2013-05-12T13:40:36.577 回答
2

我是否使用 errno 来测试 fopen() 是否成功运行,而不是“if(pFile==NULL)”不明智?

从C99 标准的7.5 Errors/3开始:

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

因此,检查errno以确定操作的成功或失败是不明智的,因为允许一个函数悲观地设置 的值errno来指示失败,即使没有。仅查询errno函数是否失败(例如,如果fopen()返回 NULLfputc()返回EOF)。

于 2013-05-12T13:36:31.153 回答
1

只是查看了手册页以确认有效的错误号都是非零的;errno绝不会被任何系统调用或库函数设置为零。

查看Linuxerrno.h手册页:我相信您应该先查看返回值,然后再查看errno.

于 2013-05-12T13:31:37.553 回答