什么样的错误将“错误”设置为非零? 为什么fopen()设置“errno”而fputc()没有?

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

首先,我使用if(errno!=0)来测试文件是否已使用fopen()成功fopen() 。 如果我尝试打开一个不存在的文件,则将errno设置为非零(在我的情况下为2),并通过在每个阶段打印出errno的值来validation它。 但是如果我打开一个现有文件,那么errno的值保持为零,因为fopen()正确地打开了文件。 在这个问题上, if(errno!=0)充当我已经注释掉的if(pFile==NULL)的完美替代品。

如果文件成功打开,并且errno仍为0 ,则控件将移至第一个else块。 这是我发现关于errno行为的混淆。 这里,由于我已经在r(读)模式下打开文件并尝试使用fputc()写入它,我期望得到的写错误将errno为非零,就像它由fopen()设置时一样无法成功打开文件。 但是即使在使用fputc()写入失败之后, errno的值仍然为零。 (这可以通过在错误写入后打印errno值来validation)。

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

 #include  #include  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; } 

文档主要告诉您哪个函数可以设置errno哪些值,但是您需要知道一些规则:

  1. 没有库函数将errno为零。
  2. 仅在函数指示发生errno时测试errno才有效(并且记录该函数以设置errno )。

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

第二点至关重要; 例如,在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 来做。

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


这记录在哪里? 它符合C标准,并通过POSIX标准加强。

ISO / IEC 9899:2011§7.5错误

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

202)因此,使用errno进行错误检查的程序应该在库函数调用之前将其设置为零,然后在后续库函数调用之前检查它。 当然,库函数可以在输入时保存errno的值,然后将其设置为零,只要在返回之前errno的值仍然为零时恢复原始值。

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

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

POSIX 2008

errno的POSIX页面说:

许多函数在errno提供错误号,其类型为int并在定义。 只有在调用明确声明要设置的函数之后,才能定义errno的值,直到它被下一个函数调用更改或者应用程序为其赋值。 只有在函数返回值指示有效时,才应检查errno的值。 应用程序应通过包含获取errno的定义。 此POSIX.1-2008卷中的任何function都不应将errno为0.除非该函数的描述指定不应修改errno ,否则未指定成功调用函数后的errno

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

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

以前版本的措辞相似。

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

从C99标准的7.5错误/ 3

程序启动时errno的值为零,但任何库函数都不会将其设置为零.159如果使用errno,则errno的值可以通过库函数调用设置为非零,无论是否存在错误 。本国际标准中的function说明中未记录。

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

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

查看Linux errno.h手册页 :我相信你应该查看返回值,然后查看errno