Стандартная функция C: getchar()
, объявлена в <stdio.h>
. Он существует в основном с незапамятных времен. Он читает один символ из стандартного ввода (stdin
), который обычно является клавиатурой пользователя, если только он не был перенаправлен (например, через символ перенаправления ввода оболочки <
или канал).
getch()
и getche()
- это старые функции MS-DOS, объявленные в <conio.h>
и все еще популярные в системах Windows. Они не являются стандартными функциями C; они существуют не во всех системах. getch
считывает одно нажатие клавиши с клавиатуры немедленно, не дожидаясь, пока пользователь нажмет клавишу «Return», и не повторяя нажатие клавиши. getche
то же самое, за исключением того, что делает эхо. Насколько я знаю, getch
и getche
всегда читаются с клавиатуры; на них не влияет перенаправление ввода.
Естественно, возникает вопрос: если getchar
является стандартной функцией, как вы используете ее для чтения одного символа, не ожидая клавиши Return или не повторяя? И ответы на эти вопросы, по крайней мере, немного сложны. (На самом деле, они достаточно сложны, поэтому я подозреваю, что они объясняют непреходящую популярность getch
и getche
, которые, если не считать ничего другого, очень просты в использовании.)
И ответ таков: getchar
не контролирует такие детали, как эхо и буферизация ввода - что касается C, то это проблемы низкого уровня, зависящие от системы.
Но полезно понять базовую модель ввода, которую предполагает getchar
. Как ни странно, обычно существует два разных уровней буферизации.
Когда пользователь вводит клавиши на клавиатуре, они читаются драйвером терминала операционной системы . Как правило, в своем режиме по умолчанию драйвер терминала немедленно отображает нажатие клавиш при вводе (чтобы пользователь мог видеть, что он печатает). Как правило, в своем режиме по умолчанию драйвер терминала также поддерживает некоторую часть редактирования строки - например, пользователь может нажать клавишу Delete или Backspace, чтобы удалить случайно набранный символ. Для поддержки редактирования строки драйвер терминала обычно собирает символы во входном буфере . Только когда пользователь нажимает Return, содержимое этого буфера становится доступным для вызывающей программы. (Этот уровень буферизации присутствует, только если стандартный ввод фактически является клавиатурой или другим последовательным устройством. Если стандартный ввод был перенаправлен в файл или канал, драйвер терминала не действует, и этот уровень буферизации не применяется.)
Пакет stdio считывает символы из операционной системы в свой собственный входной буфер. getchar
просто выбирает следующий символ из этого буфера. Когда буфер пуст, пакет stdio пытается заполнить его, читая больше символов из операционной системы.
Итак, если мы проследим, что происходит, когда программа вызывает getchar
в первый раз: stdio обнаруживает, что его входной буфер пуст, поэтому он пытается прочитать некоторые символы из операционной системы, но их нет символов пока нет, поэтому блоки read
вызывают. Между тем, пользователь может набирать некоторые символы, которые накапливаются во входном буфере драйвера терминала, но пользователь еще не нажал Return. Наконец, пользователь нажимает кнопку Return, и заблокированный вызов read
возвращает результат, возвращая целую строку символов в stdio
, которая использует их для заполнения своего входного буфера, из которого он затем возвращает первый для этого начального вызова. до getchar
, который терпеливо ждал все это время. (И затем, если программа вызывает getchar
второй или третий раз, вероятно - это еще несколько символов - следующие символы в строке, введенные пользователем - доступны во входном буфере stdio для getchar
немедленно вернуться. Подробнее об этом см. раздел 6.2 этих C примечаний к курсу .)
Но во всем этом, как вы можете видеть, getchar
и пакет stdio не имеют контроля над такими деталями, как эхо или редактирование строки ввода, потому что они обрабатываются ранее, на более низком уровне, в драйвере терминала, вшаг 1.
Итак, по крайней мере, в Unix-подобных операционных системах, если вы хотите прочитать символ, не ожидая нажатия клавиши Return, или контролировать, отображаются ли символы или нет, вы делаете это, настраивая поведениедрайвера терминала.Детали могут быть разными, но есть способ включать и выключать эхо и способ (на самом деле несколько способов) включать и выключать редактирование строки ввода.(По крайней мере, некоторые из этих деталей см. этот вопрос SO или вопрос 19.1 в старом списке C FAQ .)
Когдаредактирование строки ввода отключено, операционная система может немедленно возвращать символы (не дожидаясь клавиши возврата), потому что в этом случае не нужно беспокоиться о том, что пользователь мог набрать неправильное нажатие клавиши, которое необходимо «вернуть»"с помощью клавиши Delete или Backspace.(Но по той же причине, когда программа отключает редактирование строки ввода в драйвере терминала, если она хочет позволить пользователю исправлять ошибки, она должна реализовать свое собственное редактирование, потому что она будет видеть - то есть последовательновызовы getchar
будут возвращаться - и неправильный (ые) символ (ы) пользователя и код символа для клавиши Delete или Backspace.)