什么样的库函数会影响 errno 并将其设置为非零值会出现什么样的错误?在我的下面的程序中,我打算使用if(errno!=0)
作为条件来检查我使用的库函数是否正常运行,这就是我找到的(参见下面的代码):
首先,我使用if(errno!=0)
来测试文件是否已使用fopen()
成功打开。如果我尝试打开一个不存在的文件,那么errno
将设置为非零(在我的情况下为2),并通过在每个阶段打印出errno
的值来验证它。但是,如果我打开现有文件,则errno的值保持为零,因为fopen()
正确打开文件。在这个问题上,if(errno!=0)
充当了if(pFile==NULL)
的完美替代品,我已经注释掉了。{/ p>
如果文件成功打开,errno
仍为0
,则控件将移至第一个else
块。这是我发现errno
行为混淆的地方。在这里,因为我已经在 r(读取)模式下打开文件并尝试使用fputc()
写入文件,所以我希望产生的写入错误将errno
设置为非-zero就像fopen()
设置的那样,当它无法成功打开文件时。但即使在使用errno
写入失败之后,fputc()
的值仍然为零。 (这可以通过在错误写入后打印errno
的值来验证。)
为什么会这样?为什么一个函数fopen()
设置errno
而其他函数fputc()
面临的写错误不影响errno
时,会遇到I / O错误?如果是这样,我们如何可靠地使用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;
}
答案 0 :(得分:9)
文档主要告诉您哪个函数可以设置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 <errno.h>
来执行此操作。
我不清楚为什么您的代码在fputc()
调用时没有收到错误。在我的Mac OS X 10.8.3系统上,等效代码失败,errno
设置为9(EBADF)'错误的文件描述符'。
这在哪里记录?它符合C标准,并通过POSIX标准加强。
<errno.h>
¶3初始线程中
errno
的值在程序启动时为零(其他线程中errno
的初始值为不确定值),但任何库都不会将其设置为零函数。 202)errno
的值可以通过库函数调用设置为非零,无论是否存在错误,前提是errno
的使用未记录在本国际标准中对该功能的描述。202)因此,使用
errno
进行错误检查的程序应该在库函数调用之前将其设置为零,然后在后续库函数调用之前检查它。当然,库函数可以在进入时保存errno
的值,然后将其设置为零,只要在返回之前errno
的值仍然为零时恢复原始值。
以前版本的C标准中的措辞没有提及线程,但在其他方面类似。
请注意,C标准中fopen()
的说明未提及errno
。因此,允许按C标准设置errno
。相比之下,记录mbsrtowcs()
函数将errno
设置为EILSEQ;它可能无法将其设置为其他值,因为C标准说它不应该(尽管没有什么可以阻止实现,如果它对某些条件有更好的错误)。
errno
的POSIX页面说:
许多函数在
errno
中提供错误编号,其类型为int
,并在<errno.h>
中定义。errno
的值仅在调用明确声明为其设置的函数之后定义,并且直到它被下一个函数调用更改或者应用程序为其赋值。仅当errno
被函数的返回值指示为有效时,才应检查errno
的值。申请应通过包含<errno.h>
来获得errno
的定义。此卷POSIX.1-2008中的任何函数都不应将errno
设置为0.除非该函数的描述指定{{1},否则未成功调用函数后errno
的设置}不得修改。未指定
errno
是宏还是使用外部链接声明的标识符。如果为了访问实际对象而禁止宏定义,或者程序定义名称为errno
的标识符,则行为未定义。存储在errno中的符号值记录在所有相关页面的错误部分中。
以前版本的措辞相似。
答案 1 :(得分:2)
我是否使用errno来测试fopen()是否成功运行,而不是“if(pFile == NULL)”不明智?
来自C99标准的 7.5 Errors / 3 :
在程序启动时errno的值为零,但是任何库函数都不会将其设置为零.159)可以通过库函数调用将errno的值设置为非零,无论是否存在错误,前提是在本国际标准的功能描述中没有记录errno的使用。
因此,检查errno
以确定操作的成功或失败是不明智的,因为允许函数悲观地设置errno
的值以指示失败,即使没有。仅在函数失败时查询errno
(例如fopen()
返回NULL
或fputc()
返回EOF
)。
答案 2 :(得分:1)
只需查看手册页以确认有效的错误编号都是非零的;任何系统调用或库函数都不会将errno
设置为零。
检查the Linux errno.h
man page:
我相信您应该查看返回值,然后查看errno
。