什么样的错误将“错误”设置为非零? 为什么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
哪些值,但是您需要知道一些规则:
- 没有库函数将
errno
为零。 - 仅在函数指示发生
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()
返回NULL
或fputc()
返回EOF
)。
只需查看手册页以确认有效的错误编号都是非零的; 任何系统调用或库函数都不errno
设置为零。
查看Linux errno.h
手册页 :我相信你应该查看返回值,然后查看errno
。