5

マニュアルには次のように記載されています。errno は、システム コールまたはライブラリ関数によってゼロに設定されることはありません。しかし、知りたいのですが、次のコードでscanfによってerrnoがゼロに設定されるのはなぜですか?(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()#define次のとおりです。

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

errout末尾のクリーンアップ コードのラベルはどこにありますか。

そのため、呼び出しの前にerrnoが設定されているように見え、古い値は後で置き換えられ、変更されません。しかし、エラーが発生してそのステートメントが実行された場合 (特に、 if がに評価され、この場合はこれが発生しています)、元の値にリセットするコードがスキップされている可能性があります。そうは言っても、条件が真になるのはゼロではない場合のみであり、ここではそうではないようです。したがって、このコードとは関係がないかもしれませんが、これは私が設定されているのを見ることができる唯一の場所ですに。コメントが示唆するように、それ自体が をいじり、 に設定できます。これは に初期化されます0inchar()errnoifinchar()EOFerrnoerrno == EINTRerrno0inchar()errnoerrnoinchar_errno0inchar_errno223行目なので、更新されていないが割り当てられる他の実行パスがある可能性もありerrnoます。

于 2013-10-20T14:30:05.187 に答える