手册告诉我们:任何系统调用或库函数都不会将errno设置为零。但是我想知道,为什么errno可以通过以下代码中的scanf设置为零?(当scanf:输入“ctrl + D”时)
#include <stdio.h>
#include <errno.h>
int main()
{
int i;
errno = 5;
printf("errno:%d\n",errno);
if (scanf("%d", &i) < 1)
perror("scanf");
printf("errno:%d\n",errno);
printf("i:%d\n", i);
return 0;
}
答案 0 :(得分:3)
我可以在glibc implementation of vfscanf()
中找到以下代码,(截至撰写本文时,链接文件中的第589-607行)scanf()
调用的实现:
if (skip_space || (fc != L_('[') && fc != L_('c')
&& fc != L_('C') && fc != L_('n')))
{
/* Eat whitespace. */
int save_errno = errno;
__set_errno (0);
do
/* We add the additional test for EOF here since otherwise
inchar will restore the old errno value which might be
EINTR but does not indicate an interrupt since nothing
was read at this time. */
if (__builtin_expect ((c == EOF || inchar () == EOF)
&& errno == EINTR, 0))
input_error ();
while (ISSPACE (c));
__set_errno (save_errno);
ungetc (c, s);
skip_space = 0;
}
input_error()
#define
为:
#define input_error() do {
errval = 1;
if (done == 0) done = EOF;
goto errout;
} while (0)
其中errout
是最后清理代码的标签。
因此看起来errno
在0
调用之前设置为inchar()
,旧值后来被替换,errno
保持不变。但是如果发生错误并且执行了if
语句(特别是,如果inchar()
计算为EOF
,这就是这种情况下发生的情况),它看起来像要重置的代码{{可以跳过1}}到其原始值。话虽如此,只有errno
并且因此不是零时才会出现这种情况,这在某些情况下似乎并非如此,所以它可能与此代码无关,但这只是一个地方我可以看到errno == EINTR
设置为errno
。正如评论所示,0
本身会混淆inchar()
,并且可以将errno
设置为errno
,在第223行初始化为inchar_errno
,所以也有可能还有一些其他执行路径0
未更新,但无论如何都被分配到inchar_errno
。
答案 1 :(得分:2)