setvbuf not able to make stdin unbuffered
Asked Answered
N

2

13

My main intention was to make getchar return as soon as it gets a character instead of waiting for the ENTER key. I tried this

int main()
{
    setvbuf(stdin,NULL,_IONBF,0);
    getchar();

    return 0;
}

Comparing this with the prototype of setvbuf

setvbuf ( FILE * stream, char * buffer, int mode, size_t size );

it should set stdin to unbuffered mode.

But still getchar() keeps waiting for ENTER

I've seen related posts like this

Printing while reading characters in C

which are suggesting alternate methods to make stdin unbuffered. But I am curious to know as to why setvbuf method does not work

Neologism answered 20/4, 2012 at 13:49 Comment(3)
You must call setvbuf() before any "movement" on the stream ... so first thing in main().Dandy
@Dandy I updated my post to reflect what I tried. But still it doesn't workNeologism
I think the problem is not with setvbuf(). I tried your program with and without setvbuf() and the behaviour is different. Without setvbuf() all characters up to and including the ENTER are consumed (even though it is consumed only after typing ENTER); with setvbuf() only the first character is consumed, the remaining characters are used as a following bash command.Dandy
H
22

The terminal driver doesn't return anything until you hit return, even if the read() operation would accept what's already there.

To get character-by-character input from a terminal, you have to get it out of canonical mode into raw or cbreak mode, and that requires different operations altogether. Take a look at the POSIX manual on 'General Terminal Interface' for how to control the terminal. Or consider using the curses library.

See also: Canonical vs non-canonical terminal input

Hols answered 20/4, 2012 at 14:15 Comment(2)
setvbuf(stdin,NULL,_IONBF,0); is supposed to do that right? I mean setvbuf works fine for all file pointers but not for stdin?Neologism
No. setvbuf() just tells the standard I/O library in your program to use no buffer; it doesn't tell the terminal driver anything.Hols
A
1

In case you are trying this under Linux or another Unix-like system, it is the terminal that buffers the input and only passes an entire line. You can use ncurses to circumvent this:

#include <ncurses.h>

int main()
{
    initscr();
    getch();
    endwin();

    return 0;
}

Compile with:

gcc -o main main.c -lncurses
Allhallowtide answered 20/4, 2012 at 14:24 Comment(1)
Thanks for the reply. I saw these alternate methods, but I was curious as to why setvbuf doesn't workNeologism

© 2022 - 2024 — McMap. All rights reserved.