Search code examples
cposix

why doesn't read() work after scanf()?


OK this is a stupid question, I am sure I "should" know this but somehow I don't...

FILE structure wraps file descriptor, so if I fscanf that should advance the file descriptor.

But for this program compiled to foobar:

#include <stdio.h>
#include <unistd.h>

int main() {
    char c;

    scanf("%c", &c);
    printf("scanned %c\n", c);

    read(STDIN_FILENO, &c, 1);
    printf("read %c\n", c);

    read(STDIN_FILENO, &c, 1);
    printf("read %c\n", c);
}

>echo bcd | ./foobar
scanned b
read b
read b

appears the file descriptor did not advance, because the first read reads b. What is even more surprising, the second one also reads b (even though, if I omit the scanf, then first read reads b and the second one, c).

I am sure this is obvious and I am really embarrased to ask why. I just never followed scanf with read before.

I know scanf is a bad idea overall, but in my case it is OK because I control the other end of the pipe, and it is convenient for me to do this sequence.


Solution

  • The stdin stream will itself perform a read to fill an entire buffer, which is likely thousands of characters wide. This leaves nothing for your read system calls. scanf just pulls characters from that buffer.

    Your subsequent read system calls are actually returning 0 (no bytes read due to end of file) and not putting any data in c, which therefore retains its value 'b'. Your program is oblivious to the situation because it isn't checking the return value.