The manual tells us:errno is never set to zero by any system call or library function. But I want to know, Why errno can set to zero by scanf in following codes?(when scanf:enter the"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;
}
The scanf routine is designed to read input until a character is an input that conflicts with the format string. When such a character is read, then and only then does scanf return. So, if there is no input available, scanf just waits.
A single Ctrl-D will flush the typed 'chars' and printing them. Then after that it will wait again for input, although an EOF has been sent with the Ctrl-D . If we press Ctrl-D again the 2nd time directly after the 1st (2x) or just Enter it will terminate.
scanf() just stops once it encounters a whitespace as it considers this variable "done".
We should use "%[^\n]", which tells scanf() to take input string till user presses enter or return key. Scanf scans till user presses enter or till user presses return key.
I can find the following code in the glibc implementation of vfscanf()
, (line 589-607 in the linked file, as of the time of writing) which the implementation of scanf()
calls:
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()
is #define
d as:
#define input_error() do {
errval = 1;
if (done == 0) done = EOF;
goto errout;
} while (0)
where errout
is the label for the cleanup code at the end.
So it looks like errno
is getting set to 0
prior to the inchar()
call, and the old value is later replaced, leaving errno
unchanged. But if an error occurs and that if
statement executes (notably, if inchar()
evaluates to EOF
, which is what is happening in this case), it looks like the code to reset errno
to its original value may be being skipped. That being said, the condition will only be true if errno == EINTR
and therefore not zero, which certainly doesn't appear to be the case, here, so it may have nothing to do with this code, but this is only place I can see errno
being set to 0
. inchar()
itself does mess around with errno
, as the comment suggests, and can set errno
to inchar_errno
, which is initialized to 0
on line 223, so it's also possible there's some other execution path where inchar_errno
is not updated but gets assigned to errno
anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With