КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Использование порта
Операционные системы, отличные от ОС UNIX. Комбинированное переключение. Переключение ввода. Переключение вывода. Чтение файла. Чтение строки. 9.4. Переключение и работа с файлами. 9.5. Операционная система UNIX. 9.6. Системно-зависимые средства: порты ввода-вывода микропроцессоров INTEL 8086/8088.
5. Функции и переключение ввода-вывода. В вычислительной технике слова «ввод» и «вывод» применяются в нескольких разных смыслах. Мы можем говорить об устройствах ввода и вывода, таких, как терминалы, накопители на магнитных дисках, точечно-матричные принтеры и т. п., или о данных, используемых при вводе и выводе, или же, наконец, о функциях, реализующих ввод и вывод. Основной целью данной темы является обсуждение функций, применяемых при вводе и выводе, но, кроме этого, мы коснемся и двух других аспектов этого понятия. Под функциями ввода-вывода подразумеваются функции, которые выполняют транспортировку данных в программу и из нее. Мы уже использовали две такие функции: printf() и scanf(). Теперь же рассмотрим несколько других возможностей, предоставляемых языком Си. В языке Си имеется много функций ввода-вывода такого типа, например printf() и scanf(). Ниже мы рассмотрим функции getchar() и putchar(). Эти две функции осуществляют ввод и вывод одного символа при каждом обращении к ним. На первый взгляд, выполнение операций подобным образом может показаться довольно странным, так как, учитывая все сказанное выше, мы уже можем с легкостью осуществить ввод нескольких символов подряд. Но этот способ ввода данных лучше соответствует возможностям машины. Более того, такой подход служит основой построения большинства программ обработки текстов, являющихся последовательностями обычных слов. 9.1. Ввод и вывод одного символа: функции getchar() и putchar(). Функция getchar() получает один символ, поступающий с пульта терминала (и поэтому имеющий название), и передает его выполняющейся в данный момент программе. Функция putchar() получает один символ, поступающий из программы, и пересылает его для вывода на экран. Ниже приводится пример очень простой программы. Единственное, что она делает, это принимает один символ с клавиатуры и выводит его на экран. // ввод-вывод1 #include <stdio.h> void main() { char ch; ch = getchar(); // строка 1 putchar (ch); // строка 2 }
Функция putchar() имеет один аргумент. При ее вызове необходимо в скобках указать символ, который требуется вывести на печать. Правильным обращением к функции putchar() является указание любого из этих аргументов при ее вызове.
putchar ('S'); /* напомним, что символьные */ putchar (' \n'); /* константы заключаются в апострофы */ putchar ('\007'); putchar (ch); /* ch — переменная типа char */ putchar (getchar ());
Форму записи, приведенную в последнем примере, мы можем использовать для того, чтобы представить нашу программу в следующем виде:
#include <stdio.h> void main(void) { putchar (getchar()); }
Такая запись очень компактна и не требует введения вспомогательных переменных. Кроме того, в результате компиляции такая программа оказывается более эффективной, но, пожалуй, менее понятной.
9.2. Буферы. При выполнении данной программы (любой из двух ее версий) вводимый символ в одних вычислительных системах немедленно появляется на экране («эхо-печать»), в других же ничего не происходит до тех пор, пока вы не нажмете клавишу [ввод]. Первый случай относится к так называемому «небуферизованному» (прямому) вводу, означающему, что вводимый символ оказывается немедленно доступным ожидающей программе. Например, работа программы в системе, использующей буферизованный ввод, будет выглядеть следующим образом:
Вот длинная входная строка. [ввод] В
В системе с небуферизованным вводом отображение на экране символа В произойдет сразу, как только вы нажмете соответствующую клавишу. Результат ввода-вывода при этом может выглядеть, например, так:
ВВот длинная входная строка.
Символ В, появившийся на второй позиции данной строки, — это непосредственный результат
Зачем нужны буферы? Во-первых, оказывается, что передачу нескольких символов в виде одного блока можно осуществить гораздо быстрее, чем передавать их последовательно по одному. Во-вторых, если при вводе символов допущена ошибка, вы можете воспользоваться корректирующими средствами терминала, чтобы ее исправить. И когда в конце концов вы нажмете клавишу [ввод], будет произведена передача откорректированной строки.
9.3. Чтение данных. Теперь возьмемся за что-нибудь несколько более сложное, чем чтение и вывод на печать одного символа — например, за вывод на печать групп символов. Желательно также, чтобы в любой момент можно было остановить работу программы; для этого спроектируем ее так, чтобы она прекращала работу при получении какого-нибудь специального символа, скажем *. Поставленную задачу можно решить, используя цикл while:
// ввод-вывод2 // ввод и печать символов до поступления завершающего символа #include <stdio.h> #define STOP '*' void main(void) { char ch; ch=getchar(); // строка 9 while (ch!= STOP){ // строка 10 putchar(ch); // строка 11 ch=getchar(); //строка 12 } } При первом прохождении тела цикла функция putchar() получает значение своего apгумента в результате выполнения оператора, расположенного в строке 9; в дальнейшем, вплоть до завершения работы цикла, значением этого аргумента является символ, передаваемый программе функцией getchar(), расположенной в строке 12. Мы ввели новую операцию отношения!=, смысл которой выражается словами «не равно». В результате всего этого цикл while будет осуществлять чтение и печать символов до тех пор, пока не поступит признак STOP. Мы могли бы опустить в программе директиву #define и использовать лишь символ * в операторе while, но наш способ делает смысл данного знака более очевидным.
9.3.1. Чтение строки. Одной из возможностей является использование символа «новая строка» (\n). Для этого нужно лишь переопределить признак STOP:
#define STOP '\n'
Какой это даст эффект? Очень большой: ведь символ «новая строка» пересылается при нажатии клавиши [ввод].
9.3.2. Чтение файла. Каким может быть идеальный признак STOP? Это должен быть такой символ, который обычно не используется в тексте и, следовательно, не приводит к ситуации, когда он случайно встретится при вводе, и работа программы будет остановлена раньше, чем мы хотели бы. Проблема подобного сорта не нова, и, к счастью для нас, она уже была успешно решена проектировщиками вычислительных систем. На самом деле задача, которую они рассматривали, была несколько отличной от нашей, но мы вполне можем воспользоваться их решением. Занимавшая их проблема касалась «файлов». Файлом можно назвать участок памяти, в который помещена некоторая информация. Обычно файл хранится в некоторой долговременной памяти, например, на гибких или жестких дисках, или на магнитной ленте. Чтобы отмечать, где кончается один файл и начинается другой, полезно иметь специальный символ, указывающий на конец файла. Это должен быть символ, который не может появиться где-нибудь в середине файла, точно так же как выше нам требовался символ, обычно не встречающийся во вводимом тексте. Решением указанной проблемы служит введение специального признака, называемого «End-of-File» (конец файла), или EOF, для краткости. Выбор конкретного признака EOF зависит от типа системы: он может состоять даже из нескольких символов. Но такой признак всегда существует, и компилятор с языка Си, которым вы пользуетесь, конечно же знает, как такой признак действует в вашей системе.
Каким образом можно воспользоваться символом EOF? Обычно его определение содержится в файле <stdio.h>. Общеупотребительным является определение:
#define EOF (- 1)
Это дает возможность использовать в программах выражения, подобные, например, такому:
while ((ch=getchar())!= EOF)
Поэтому мы можем написать пporpaммy, осуществляющую ввод и эхо-печать символов, так:
// ввод-вывод4 #include <stdio.h> void main(void) { int ch; while ((ch = getchar())!= EOF) putchar (ch); }
// X23.C #include <stdio.h> void main(void) { int ch; int count=0; printf("Для окончания работы введите <CTRL/Z>\n"); while ((ch=getchar())!= EOF) { putchar(ch); count++; } printf("\n Было введено %d символов.\n",count); } Отметим следующие моменты: 1. Нам не нужно самим определять признак EOF, поскольку заботу об этом берет на себя файл <stdio.h>. 2. Мы можем не интересоваться фактическим значением символа EOF, поскольку директива #define, имеющаяся в файле <stdio.h>, позволяет нам использовать его символическое представление. 3. Мы изменили тип переменной ch с char на int. Мы поступили так потому, что значениями переменных типа char являются целые числа без знака в диапазоне от 0 до 255, а признак EOF может иметь числовое значение -1. Эта величина недопустима для переменной типа char, но вполне подходит для переменной типа int. К счастью, функция getchar() фактически возвращает значение типа int, поэтому она в состоянии прочесть символ EOF. 4. Переменная ch целого типа никак не может повлиять на работу функции putchar(). Она просто выводит на печать символьный эквивалент значения аргумента. 5. При работе с данной программой, когда символы вводятся с клавиатуры, необходимо уметь вводить признак EOF. He думайте, что вы можете просто указать буквы E-O-F или число -1. (Число -1 служит эквивалентом кода ASCII данного символа, а не самим этим символом.) Вместо этого вам необходимо узнать, какое представление используется в вашей системе. В большинстве реализаций операционной системы UNIX, например, ввод знака [CTRL/D] (нажать на клавишу [D], держа нажатой клавишу [CTRL]) интерпретируется как признак EOF. Во многих микрокомпьютерах для той же цели используется знак [CTRL/Z].
Приведем результат работы программы ввод-вывод4 в системе, обладающей буферизованным вводом: Каждый раз при нажатии клавиши [ввод] производится обработка символов, попавших в буфер, и копия строки выводится на печать. Это продолжается до тех пор, пока мы не введем признак EOF.
9.4. Переключение и работа с файлами. Операция переключения — это средство ОС UNIX, а не самого языка Си. Но она оказалась настолько полезной, что при переносе компилятора с языка Си на другие вычислительные системы часто вместе с ним переносится в какой-то форме и эта операция. Более того, многие из вновь созданных операционных систем, таких, как MS-DOS 2, включают в себя данное средство. Поэтому, даже если вы не работаете в среде ОС UNIX существует большая вероятность того, что вы в той или иной форме сможете воспользоваться операцией переключения. Мы обсудим сначала возможности этой операции в ОС UNIX, а затем и в других системах.
9.5. Операционная система UNIX. 9.5.1. Переключение вывода. Символ < служит обозначением операции переключения, используемой в ОС UNIX. Выполнение указанной операции приводит к тому, что содержимое файла words будет направлено в файл с именем getput4. Сама программа ввод-вывод4 не знает (и не должна знать), что входные данные поступают из некоторого файла, а не с терминала; на ее вход просто поступает поток символов, она читает их и последовательно, по одному выводит на печать до тех пор, пока не встретит признак EOF. В операционной системе UNIX файлы и устройства ввода-вывода в логическом смысле представляют собой одно и то же, поэтому теперь файл для данной программы является устройством ввода-вывода. Если вы попробуете ввести команду
getput4 < words
9.5.2. Переключение ввода. Теперь предположим (если вы еще не устали и в состоянии что-нибудь предположить), вам хочется, чтобы слова, вводимые с клавиатуры, попадали в файл с именем mywords. Для этого вы должны ввести команду
getput4 > mywords
и начать ввод символов. Символ > служит обозначением еще одной операции переключения, используемой в ОС UNIX. Ее выполнение приводит к тому, что создается новый файл с именем mywords, а затем результат работы программы ввод-вывод4, представляющий собой копию вводимых символов, направляется в данный файл. Если файл с именем mywords уже существует, он обычно уничтожается, и вместо него создается новый.
9.5.3. Комбинированное переключение. Предположим теперь, что вы хотите создать копию файла mywords и назвать ее savewords. Введите для этого команду
getput4 < mywords >savewords
и требуемое задание будет выполнено. Команда
getput4 >savewords < mywords
приведет к такому же результату, поскольку порядок указания операций переключения не имеет значения. Нельзя использовать в одной команде один и тот же файл и для ввода и для вывода одновременно.
getput4 <mywords >mywords НЕПРАВИЛЬНО
Причина этого заключается в том, что указание операции >mywords приводит к стиранию исходного файла перед его использованием в качестве входного. Теперь, мы думаем, настало время суммировать правила, касающиеся использования двух операций переключения < и >. 1. Операция переключения связывает выполняемую программу (в том числе и стандартные команды ОС UNIX) с некоторым файлом. Она не может использоваться для связи одного файла с другим или одной программы с другой. 2. Имя выполняемой программы должно стоять слева от знака операции, а имя файла — справа от него. 3. При использовании этих операций ввод не может осуществляться более чем из одного файла, а вывод — более чем в один файл. 4. Обычно между именем и операцией пробелы не обязательны кроме тех редких случаев, когда используются некоторые символы специального назначения в интерпретаторе команд UNIX. Мы могли бы писать, например, так: getput4< words, или, что более предпочтительно, getput4 < words.
9.5.4. Операционные системы, отличные от ОС UNIX. Здесь мы главным образом рассмотрим, чем отличаются другие операционные системы от ОС UNIX; поэтому, если вы пропустили предыдущий раздел, вернитесь назад и прочтите его (это не займет у вас много времени). Все отличия можно разделить на две группы: 1. В других операционных системах реализована операция переключения. 2. Компиляторы с языка Си предоставляют возможность использовать операцию переключения.
Мы не можем рассмотреть все возможные операционные системы, поэтому приведем пример только одной из них, но весьма широко распространенной. Это система MS-DOS 2; она вначале была просто «отпрыском» ОС СР/М, а сейчас самостоятельно развивается в сторону операционной системы XENIX, подобной ОС UNIX. В версию 2 MS-DOS были введены операции переключения <и>; они работают в ней точно так же, как было описано в предыдущем разделе. У нас нет возможности рассмотреть все компиляторы с языка Си. Однако в пяти из шести версий компилятора, предназначенных для микрокомпьютеров, с которыми мы имели дело, для указания операции переключения используются символы <и>. Операция переключения, реализуемая компилятором с языка Си, отличается от аналогичной операции, выполняемой ОС UNIX, в двух аспектах: 1. Указанная операция выполняется при работе программ, написанных только на Си, в то время как в ОС UNIX она может использоваться при работе любой программы. 2. Между именем программы и знаком операции должен быть один пробел, а между знаком операции и именем файла пробел должен отсутствовать. Ниже приведен пример правильной команды getput4 < words
Комментарий. Операция переключения — это простое, но мощное средство. С ее помощью мы можем превратить нашу крошечную программу ввод-вывод4 в инструмент для создания, чтения и копирования файлов. Данный способ служит иллюстрацией подхода, принятого в языке Си (и ОС UNIX) и заключающегося в конструировании простых средств, которые можно комбинировать различные образом для выполнения конкретных задач. Резюме: как переключать ввод и вывод. На большинстве машин, в которых реализован компилятор с языка Си, операцию переключения можно использовать либо для всех программ, благодаря поддержке операционной системы, либо только для программ, написанных на Си, благодаря наличию компилятора с этого языка. Ниже prog будет именем выполняемой программы, a file1 и file2 — именами файлов. Переключение вывода в файл: > prog >file1
Переключениe ввода из файла: < prog <file2
Комбинированное переключение: prog <file2 >file1 или prog >file1 <file2
В обеих формах записи файл с именем file2 используется для ввода данных, а файл с именем file1 — для вывода. Расположение пробелов. Некоторые системы (в особенности компиляторы с языка Си) требуют наличия пробела слева от знака операции переключения и его отсутствия справа от этого знака. Другие системы (ОС UNIX, например) допускают любое число пробелов (в том числе и ни одного) слева и справа от знака данной операции. Графический пример. Мы можем воспользоваться функциями getchar() и putchar() для изображения геометрических фигур при помощи символов. Ниже приведена программа, которая это делает. Она читает символ, а затем печатает его некоторое число раз, зависящее от кода ASCII этого символа. Кроме того, она печатает на каждой строке требуемое число пробелов, чтобы текст оказывался в центре строки.
// фигуры // изображает симметричную фигуру из символов #include <stdio.h> void main(void) { int ch; // переменная для ввода символа int index; int chnum; while ((ch = getchar())!= '\n'){ chnum = ch %26; // получение числа от 0 до 25 index = 0; while (index++ <(30 - chnum)) putchar (' '); // печать пробелов сдвига к центру index = 0; while (index++ <(2* chnum + 1)) putchar (ch); // повторная печать символа putchar (' \n'); } }
Единственный новый технический прием здесь — это использование подвыражений, таких, как (30-chnum), при записи условий в циклах while. Один цикл while управляет печатью необходимого числа начальных пробелов в каждой строке, а второй — выводом символов на печать. Результат работы программы зависит от данных, которые вводятся. Если, например, вы введете What's up? (Что случилось?)
то на экране появится следующее:
9.6. Системно-зависимые средства: порты ввода-вывода микропроцессоров INTEL 8086/8088. В компьютере типа IBM PC кроме ИС 8088 имеются и другие устройства, например клавиатура, громкоговоритель, возможно, накопитель на мини-кассете или магнитном диске, монитор, встроенная память, таймеры, а также микропроцессоры для управления потоком данных. Центральный процессор (встроенный в кристалл 8088) должен иметь возможность взаимодействовать с остальными частями компьютера. Некоторые из таких взаимодействий осуществляются при помощи адресов памяти, другие — при помощи «портов» ввода-вывода. У микропроцессора 8088 имеется 65536 портов, которые могут использоваться при различных взаимодействиях. Для связи с этим микропроцессором каждому устройству назначается свой определенный порт или порты. (Заметим, что используются не все 65536 портов!) Например, порты 992, 993, 1000—1004 используются для связи с адаптером цветной графики. Работа громкоговорителя управляется портом с номером 97. Это выглядит несколько проще, чем управление адаптером цветной графики, поэтому мы используем его для иллюстрации работы портов ввода-вывода.
9.6.1. Использование порта. Существуют две операции, которые могут выполняться с помощью порта: микропроцессор 8088 может послать информацию в подсоединенное устройство или прочитать данные из него. В языке ассемблера эти операции выполняются при помощи команд OUT и IN, а в языке Си использование указанных средств зависит от компилятора. Некоторые из них предоставляют возможность вызова специальных функций (в соответствии с тем, как это обычно делается в языке Си). В компиляторах Lattice С и Supersoft С, например, с этой целью применяются функции outp() и inp(), в других же аналогичные функции могут носить другие имена. Если вы работаете с компилятором, в котором такие возможности отсутствуют, для задания указанных функций можно либо воспользоваться ассемблером, либо просто включить в свою программу соответствующий ассемблерный код (что очень просто). В любом случае вам необходимо ознакомиться с документацией по вашему компилятору. Пока же будем предполагать, что у вас имеется возможность вызова функций outp() и inp(). Приведем пример программы, представляющей собой первую попытку извлечь звуковой сигнал из громкоговорителя:
/* сигнал1 */ /* заставляет громкоговоритель подавать сигнал */ #include <stdio.h> void main() { int store; /* запоминание начального значения с помощью порта 97 */ store= inp (97); printf("пopт 97 = %d\n", store);/* проверка результатов */ /* посылает 79 в порт 97; включение громкоговорителя */ outp(97, 79); /* восстановление начального значения */ outp(97, store); }
/* X25.C */ #include <stdio.h> #include <dos.h> #define MAX1 32000 #define MAX2 3000 void main() { int store, count=0; store=inport(97); while(count++ < MAX1) outport(97,79); outport(97,store); /*....................................... */ count=0; while(count++ < MAX1) ; count=0; while(count++ < MAX1) ; count=0; while(count++ < MAX1) ; /*....................................... */ count=0; while(count++ < MAX2) outport(97,79); outport(97,store); }
Несмотря на то что, по-видимому, вы и сами можете догадаться, что выполняют функции inp() и outp(), ниже приведем их формальное описание: inp(номер порта) Эта функция возвращает (т. е. формирует) 8-разрядное целое значение (которое преобразуется в 16-разрядное число типа int путем добавления нулей слева), полученное из порта ввода с указанным номером. Обращение к ней не зависит от номера подключенного порта. outp (номер порта, значение) Эта функция передает 8-разрядное целое значение в порт вывода с указанным номером.
Заметим, что один и тот же порт может быть как портом ввода, так и портом вывода в зависимости от того, как он используется. 10. Выбор вариантов. 10.1. Операции отношения и выражения. 10.2. Понятие «истина». 10.3. Условные операторы.
Дата добавления: 2015-01-03; Просмотров: 777; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |