Getchar () loops over EOF when STDIN is passed through a pipe

I am in front of something that I cannot explain. There is no better way to explain it than with an example:

#include <stdio.h>

int main ()
{
    char c;
    while (1) {
        c = getchar();
        printf("%x\n", c);
    }
   return(0);
}

      

If I run this command, it just iterates endlessly like this:

$ echo -n "A" | ./binary
41
ffffffff
ffffffff
ffffffff
ffffffff
...

      

From what I know and what I read ( Confusion about how the getchar () loop works internally ) I thought it would echo -n "A"

send A

to stdin and then fire an EOF event (I'm not sure if EOF really is) once , so my loop will execute at most two times and then wait for new input to stdin .

But no, it is iterating over EOF and I don't understand why.

I ran this command to try and understand:

$ echo -n "A" | strace ./binary
read(0, "A", 4096)                      = 1
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ffff7ff6000
write(1, "41\n", 341
)                     = 3
read(0, "", 4096)                       = 0
write(1, "ffffffff\n", 9ffffffff
)               = 9
read(0, "", 4096)                       = 0
write(1, "ffffffff\n", 9ffffffff
)               = 9
...

      

So, it seems that read () doesn't read anything and returns 0, which is interpreted by getchar () as EOF. But why, oh, why is it so repetitive, whereas when I execute this binary in the usual way, it works as expected:

$ ./binary
A
41
a
B
42
a
^C
$

      

(The above output might be a little confusing, but when I entered A, then Return, I sent A

and then \n

(0x0a) to stdin, so the binary just displays them in their hexa views, 41

and A

)

Can anyone explain this to me? What did I miss?

Thanks a lot for reading!

+3


source to share


3 answers


Once met EOF

, it getchar

will return immediately with a return value EOF

. The stream pointer for the stream will not advance, it will remain at the EOF marker. Subsequent calls getchar

will also return immediately, since the thread is still on the mark EOF

.



Note that this is different from the behavior when stdin

connected to an input device. In this case, it getchar

will pause, waiting for further input if the input buffer is empty. getchar

will not return EOF

until sent to the input device EOF

( CTRL-D

send EOF

from keyboard in Linux).

+5


source


getchar () returns int, not char. A higher return value allows you to search for an EOF return value that is -1. This is the return value for errors and end of file. Changing the type from c to int will not change the behavior of printf.



#include <stdio.h>

int main ()
{
    int c;
    while (1) {
        c = getchar();
        if ( c == EOF) {
            break;
        }
        printf("%x\n", c);
    }
   return(0);
}

      

+4


source


First, EOF is -1, which is 0xFFFFFFFF.

the system function 'getchar ()' returns an int, not a char.

So, for comparison, 'c' should be an int, not a char.

Now, to exit the while loop, there must be a comparison with some condition that must be true in order to continue in the loop.

suggest using the following code model.

#include <stdio.h>

int main ( void )  //<< for main, better to use 'void' rather than empty braces
{
    int c; //<< because getchar() returns an int, not a char

    // following loop has EOF as exit condition
    // note in C, && is lower presidence than = and != so is evaluated last
    // note in C, && is evaluated from left to right
    // note to help the compiler to catch errors,
    //      always place the literal on the left of a comparison
    while (c = getchar() && EOF != c) 
    {
        printf("%x\n", c);
    }
   return(0);
} // end function: main

      

+2


source







All Articles