setvbuf не может сделать stdin небуферизованным

Мое основное намерение состояло в том, чтобы заставить getchar возвращаться, как только он получает символ, вместо того, чтобы ждать нажатия клавиши ENTER. я пробовал это

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

    return 0;
}

Сравнивая это с прототипом setvbuf

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

он должен установить stdin в небуферизованный режим.

Но getchar() продолжает ждать ENTER

Я видел похожие сообщения, подобные этому

Печать при чтении символов в C

которые предлагают альтернативные методы сделать stdin небуферизованным. Но мне любопытно узнать, почему метод setvbuf не работает


person Pavan Manjunath    schedule 20.04.2012    source источник
comment
Вы должны вызвать setvbuf() перед любым движением в потоке... поэтому первым делом в main().   -  person pmg    schedule 20.04.2012
comment
@pmg Я обновил свой пост, чтобы отразить то, что я пробовал. Но все равно не работает   -  person Pavan Manjunath    schedule 20.04.2012
comment
Думаю проблема не в setvbuf(). Я пробовал вашу программу с setvbuf() и без нее, и поведение было другим. Без setvbuf() используются все символы до ENTER включительно (даже если он используется только после ввода ENTER); с setvbuf() потребляется только первый символ, остальные символы используются в качестве следующей команды bash.   -  person pmg    schedule 20.04.2012


Ответы (2)


Драйвер терминала ничего не возвращает, пока вы не нажмете return, даже если операция read() примет то, что уже есть.

Чтобы получить посимвольный ввод с терминала, вы должны вывести его из канонического режима в необработанный режим или режим cbreak, а для этого требуются совершенно другие операции. Ознакомьтесь с руководством по POSIX в разделе 'Общий интерфейс терминала'. как управлять терминалом. Или рассмотрите возможность использования библиотеки curses.

См. также: Канонический и неканонический ввод терминала

person Jonathan Leffler    schedule 20.04.2012
comment
setvbuf(stdin,NULL,_IONBF,0); должен делать это правильно? Я имею в виду, что setvbuf отлично работает для всех указателей файлов, но не для stdin? - person Pavan Manjunath; 20.04.2012
comment
Нет. setvbuf() просто говорит стандартной библиотеке ввода-вывода в вашей программе не использовать буфер; это ничего не говорит драйверу терминала. - person Jonathan Leffler; 20.04.2012

Если вы пытаетесь сделать это под Linux или другой Unix-подобной системой, терминал буферизует ввод и пропускает только всю строку. Вы можете использовать ncurses, чтобы обойти это:

#include <ncurses.h>

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

    return 0;
}

Скомпилировать с:

gcc -o main main.c -lncurses
person user1202136    schedule 20.04.2012
comment
Спасибо за ответ. Я видел эти альтернативные методы, но мне было любопытно, почему setvbuf не работает - person Pavan Manjunath; 20.04.2012