5

手册告诉我们:任何系统调用或库函数都不会将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;
}
4

2 回答 2

3

我可以在glibc 的实现中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()#defined 为:

#define input_error()         do {     
                          errval = 1; 
                          if (done == 0) done = EOF;
                          goto errout; 
                        } while (0)

errout最后清理代码的标签在哪里。

所以看起来在调用之前errno被设置为,旧值后来被替换,保持不变。但是,如果发生错误并且该语句执行(特别是,如果计算结果为,这就是在这种情况下发生的情况),看起来重置为其原始值的代码可能会被跳过。话虽这么说,条件只有在并且因此不为零时才为真,这显然不是这种情况,在这里,所以它可能与这段代码无关,但这是我唯一能看到被设置的地方到. 正如评论所暗示的那样,它本身确实与,并且可以设置为,初始化为0inchar()errnoifinchar()EOFerrnoerrno == EINTRerrno0inchar()errnoerrnoinchar_errno0在第 223 行,因此也可能存在其他一些inchar_errno未更新但仍被分配到的执行路径errno

于 2013-10-20T14:30:05.187 回答
2

This is a bug. You should report it. (That page is for GCC bugs. GCC only supplies parts of the standard library; I am not sure whether scanf is part of GCC. The Red Hat bug-reporting system is here.)

Per C 2011 (N1570) 7.5 3: “The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function.”</p>

N1570 is not the official version of the standard, but it is close, and the official version of the 1999 standard had the same specification without the thread aspect: “The value of errno is zero at program startup, but is never set to zero by any library function.”</p>

于 2013-10-20T13:47:03.520 回答