/
Автор: Скляров В.А.
Теги: компьютерные технологии программирование программное обеспечение языки программирования издательство высшая школа
ISBN: 5-339-00630-1
Год: 1992
Текст
В.А.СКЛЯРОВ
ПРОГРАММНОЕ
И
ЛИНГВИСТИЧЕСКОЕ
ОБЕСПЕЧЕНИЕ
ПЕРСОНАЛЬНЫХ
ЭВМ
СИСТЕ/ИЫ
ОБШЕГО
Н43Н4ЧЕНИЯ
СПРАВОЧНОЕ ПОСОБИЕ
МИНСК ВЫШЭИШАЯ ШКОЛА 1992
ББК 32.973-01я2
С43
УДК 681.3.06(035.5)
Рецензент: заведующий кафедрой конструи-
рования электронно-вычислительной аппаратуры Ря-
занского радиотехнического института доктор техни-
ческих наук, профессор В. П. Корячка
Редактор издательства С. Ю. Липец
2404090000—117
С-------------------71 — 91
М 304 (03) —92
ISBN 5-339-00630-1
© В. А. Скляров, 1992
Скляров В. А.
С43 Программное и лингвистическое обеспечение
персональных ЭВМ. Системы общего назначения:
Справ, пособие,—Мн.: Выш. шк„ 1992,— 462 с.: ил.
ISBN 5-339-00630-1.
Описываются основные современные программные и лингви-
стические средства персональных ЭВМ. Рассмотрены уровни
взаимодействия пользователя с машиной, работа 'с различными
контроллерами, языки программирования ассемблера, СИ,
ПАСКАЛЬ, ПРОЛОГ, компоненты операционных систем (вклю-
чая прерывания ОС и BIOS), текстовые редакторы. Приведены
сведения о библиотеках, графических системах, инструменталь-
ных средах. Даны примеры программ с содержательными ком-
ментариями.
Предназначена для студентов всех специальностей, инже-
неров, аспирантов научных работников, использующих персо-
нальные ЭВМ.
2404090000— 117
С----------------71—91 ББК 32.973-01я2
М 304(03)—92
ПРЕДИСЛОВИЕ
В настоящее время персональные ЭВМ широко
внедряются во все сферы учебной, научной и произ-
водственной деятельности. Многие из них конкури-
руют с большими ЭВМ и в ряде случаев не уступают
им по своим характеристикам. Производительность
массовых современных персональных ЭВМ превы-
шает несколько миллионов операций в секунду, объем
оперативной памяти достигает десятка мегабайт.
Особую популярность в нашей стране и за рубежом
получили машины семейств IBM PC (отечественные
модели ЕС 1840, ЕС 1841, ЕС 1842, «Искра 1030»,
«Истра 4816» и др.) и PS/2. Все они программно
совместимы снизу вверх; для них разработано боль-
шое число программных средств, имеются трансля-
торы с языков ассемблера, ПАСКАЛЬ, СИ, БЕЙ-
СИК, ФОРТРАН-77, ПРОЛОГ, ФОРТ, ЛИСП,
МОДУЛА-2 и др. Созданы пакеты для работы
с электронными таблицами, реляционные базы дан-
ных, интегрированные прикладные системы, тексто-
вые и графические редакторы и т. п. Для успешного
и эффективного использования персональных ЭВМ
необходимо в совершенстве знать их возможности
и предоставляемые ими средства.
Каждая персональная ЭВМ имеет свои ресурсы,
выделяемые одному пользователю (программно-
доступные регистры, различного рода память, пери-
ферийное оборудование). В совокупности они обра-
зуют те средства, на которые пользователь может
воздействовать своими программами, получая от них
то, что необходимо для эффективного решения по-
ставленной задачи. Управление ресурсами персо-
нальных ЭВМ может осуществляться различными
путями. На нижнем уровне оно реализуется через
порты и средства обработки прерываний базовой
системы ввода-вывода, образующей прослойку меж-
ду аппаратурой и программным обеспечением. Далее
управление может осуществляться с помощью ко-
3
манд операционной системы (ОС) и прерываний ОС.
И, наконец, управлять можно средствами приклад-
ных программ пользователя.
Решение этих задач — дело непростое. Для этого
необходимо хорошо знать системные средства персо-
нальных ЭВМ и возможности современных языков
программирования, ориентированных на использо-
вание этих средств. Однако применение современных
приемов работы на машине позволяет в полном
смысле использовать персональные ЭВМ в качестве
необходимого инструмента для решения учебных,
научных и производственных задач.
В данном справочном пособии содержится общая
характеристика персональных ЭВМ, рассматривают-
ся структура и способы управления ее периферийным
оборудованием. Нижний уровень взаимодействия
с аппаратурой персональных ЭВМ образует комплекс
программ ОС. Наибольшую популярность завоевала
система MS-DOS, которая подробно описана в по-
собии. Значительное внимание уделяется описанию
прерываний ОС. Подробно описывается профес-
сиональный редактор X-Writer, позволяющий гото-
вить тексты на различных языках (в том числе
и на русском), строить сложные математические
формулы, рисунки и т. п. Из лингвистических средств
рассмотрены популярные алгоритмические языки
ПАСКАЛЬ и СИ, даны основные сведения о языке
программирования ПРОЛОГ, описан язык ассемб-
лера. Излагаются способы объединения программ,
написанных на разных языках. Описаны инструмен-
тальные ТУРБО системы, предоставляющие допол-
нительный сервис при работе с лингвистическими
средствами, библиотеки систем программирования,
насчитывающие сотни стандартных подпрограмм.
Наличие развитых средств отображения информации
дает возможность широко использовать персональ-
ные ЭВМ для работы с графикой. В пособии рас-
смотрены все основные графические подпрограммы,
позволяющие создавать и сохранять сложные цвет-
ные изображения, выполнять различные манипуля-
ции с ними, показаны основные приемы работы
с адаптерами видеомониторов с помощью преры-
ваний BIOS и на физическом уровне. Гл. 4 книги
написана совместно с И. Р. Булатовой, гл. 8—
с В. А. Радищевским.
4
Представленные материалы расширяют и допол-
няют серию методических разработок, изданных
в Минском радиотехническом институте в 1988-
1989 гг. В их основу легли лекции, которые автор
в течение ряда лет читал на факультете повышения
квалификации специалистов промышленности по пер-
сональным ЭВМ, а также для студентов, специа-
лизирующихся в области электронной вычислитель-
ной техники. Дано большое число примеров с ориен-
тацией на выбранные языки программирования
(преимущественно на язык СИ). Некоторые про-
граммы приведены перед описанием языков, поэтому
рассмотрение их при отсутствии или недостаточности
соответствующих знаний можно отложить либо
следует предварительно ознакомиться с гл. 5, 6.
Пособие будет полезно студентам всех специаль-
ностей, инженерам, аспирантам, научным работни-
кам, преподавателям при решении на персональ-
ных ЭВМ задач из различных прикладных областей.
Автор выражает благодарность рецензенту —
заведующему кафедрой конструирования электрон-
но-вычислительной аппаратуры Рязанского радио-
технического института доктору технических наук,
профессору В. П. Корячко, чьи рекомендации во
многом способствовали улучшению содержания ру-
кописи.
Все замечания просьба направлять по адресу:
220048, Минск, проспект Машерова, 11, издательство
«Вышэйшая школа».
Автор
УСЛОВНЫЕ СОКРАЩЕНИЯ
BIOS — базовая система ввода-вывода
ИА — исполнительный адрес
МП — микропроцессор
НГМД — накопитель на гибких магнитных дисках
ОЗУ — оперативное запоминающее устройство
ОП — оперативная память
ОС — операционная система
ПДП — прямой доступ к памяти
ПЗУ — постоянное запоминающее устройство
ПУ — периферийные устройства
ПЭВМ — персональная электронная вычислительная машина
РОН — регистр общего назначения
ТРФ — таблица размещения файлов
УСГИ —устройство для съема графической информации
ЦП — центральный процессор
1. ПЕРСОНАЛЬНЫЕ ЭВМ
1.1. НАЗНАЧЕНИЕ, СОСТАВ
И ТЕХНИЧЕСКИЕ ХАРАКТЕРИСТИКИ ПЭВМ
Персональная ЭВМ (ПЭВМ) — это небольшая по раз-
мерам универсальная микроЭВМ, предназначенная для
индивидуального пользователя. С конструктивной точки
зрения в ПЭВМ можно выделить пять основных устройств:
системный блок, клавиатуру, дисплей, накопители на
жестких и гибких магнитных дисках, печатающее устрой-
ство (принтер).
Системный блок содержит всю электронную начинку
ПЭВМ. Его главные компоненты — центральный про-
цессор (ЦП) и память: оперативное запоминающее
устройство (ОЗУ) и постоянное запоминающее устройст-
во (ПЗУ). Основой ЦП является микропроцессор (МП),
с помощью которого осуществляются выполнение ариф-
метических и логических операций над числами, обработ-
ка текстовой и графической информации, пересылка дан-
ных между регистрами и ячейками ОЗУ и т. п. В соот-
ветствии с разрядностью внутренних регистров микро-
процессоры и построенные на их основе ПЭВМ бывают
8-, 16- или 32-разрядными. Так, отечественные ПЭВМ
ЕС 1840, ЕС 1841, ЕС 1842, «Искра 1030», «Истра
4816» построены на 16-разрядных микропроцессо-
рах КР1810ВМ86 (зарубежный аналог Intel 8086),
ПЭВМ IBM PC/AT, PS/2 (модели 50, 60) — на
16-разрядных микропроцессорах Intel 80286, ПЭВМ PS/2
(модель 80) на 32-разрядных микропроцессорах Intel
80386.
Если ЦП осуществляет и координирует процесс об-
работки данных, то ОЗУ выполняет функции их хранения.
Слова информации, помещаемые в ОЗУ, обычно имеют
размер один байт (8 бит). Широко распространены ПЭВМ
с основной памятью 640 К байт и модулем расширения
объемом до нескольких мегабайт.
Кроме перечисленных главных компонентов, в состав
7
системного блока входят адаптеры (контроллеры) пери-
ферийных устройств: дисплея, накопителя на дисках,
принтера. Они выполняют функции управления, передачи
и приема необходимой информации, например обеспечи-
вают ее запись и чтение на гибком магнитном диске.
Данные между различными компонентами передаются
по системной шине, которая обеспечивает универсальный
интерфейс связи между ними.
В табл. 1.1 приведены технические характеристики
наиболее распространенных ПЭВМ. Сведения о зарубеж-
ных машинах взяты из работы [ 14].
Таблица 1.1
Название Страна МП Раз- ряд- ность Такто- вая я асто- та, МГц Объем, К байт
ОЗУ ПЗУ
IBM PC США 8088 16 4,77 256 40
IBM PC/AT США 80 286 16 8 640 120
Macintosh США 68 000 16 7,83 512 64
Olivetti PS/2: Италия 8086 16 4,77 640 64
Model 50 США 80 286 16 10 1024, расши- рение до 7 М байт 128
Model 80 США 80 386 32 16 1024, расши- рение до 16М байт 128
EC 1840 СССР К1810 16 4 128—640 8
EC 1841 СССР К1810 16 4 1024 64
«Искра 1030» «Истра 4816» СССР СССР К1810 К1810, К580 16 16 4 512 1024—4096 8
CM 1910 ГДР К1810 16 2,5 768 64
1.2. АППАРАТНЫЕ И ПРОГРАММНЫЕ
СРЕДСТВА ПЭВМ
Главным средством обработки информации в ПЭВМ
является МП. Программист, работающий на ПЭВМ, имеет
доступ к ресурсам МП, к числу которых относятся про-
граммно-доступные регистры. В них можно заносить и из
них можно считывать данные с помощью команд МП.
Совокупность программно-доступных регистров определя-
ет логическую организацию МП.
На ри'с. 1.1 показана логическая организация МП
KJP1810BM86 (Intel 8086). В составе МП 14 программно-
8
БЛОК СЕГМЕНТНЫХ РЕГИСТРОВ
0
1S
CS
□S
S3
ES
СЕГМЕНТ КОДА_______
СЕГМЕНТ ДАННЫХ
СЕГМЕНТ СТЕКА______
ЭКСТРАКОДОВЫЙ СЕГМЕНТ
БЛОК РЕГИСТРОВ ОБЩЕГО НАЗНАЧЕНИЯ 4Я
1S.0
RX
вх
сх
DX
SP
ВР
31
DI
IS RH 8
is ВН а
is СН а
is DH а
RL 0
BL и
CL 0
DL и
ЫКАЗАТЕЛЬ СТЕКА
УКАЗАТЕЛЬ БАЗЫ
ИНДЕКС-РЕГИСТР ОПЕРАНДА
ИНДЕКС-РЕГИСТР РЕЗУЛЬТАТА
АККУМУЛЯТОР
БАЗА
счетчик:
ДАННЫЕ
FРЕГИСТР АДРЕСА КОМАНД
1S_______________________0
I IP I
р РЕГИСТР ПРИЗНАКОВ
15 И 10 9 8 7 6 4 2 0
ПЕРЕПОЛНЕНИЕ —1
НАПРАВЛЕНИЕ -----
РАЗРЕШЕНИЕ
ПРЕРЫВАНИЯ
ПОШАГОВЫЙ
РЕЖИМ
ЗНАК ---
НУЛЬ ---
ВСПОМОГАТЕЛЬНЫЙ
ПЕРЕНОС
ЧЕТНОСТЬ -------
ПЕРЕНОС --------
Рис. 1.1. Логическая организация МП Intel 8086
доступных регистров. Адресуемая область памяти МП
составляет 1 М байт, и, следовательно, формат адреса
равен 20 бит. Несмотря на генерацию 20-разрядных
кодов, сам МП манипулирует логическими адресами,
содержащими 16-разрядный сегментный (базовый) адрес
и 16-разрядное внутрисегментное смещение. Механизм
сегментации предполагает разбиение всего адресуемого
пространства на области — сегменты — по 64 К байт
каждая. Начальный адрес любой такой области (20 бит)
имеет в четырех младших разрядах нули XXXXOie, т. е.
сегменты могут начинаться на границах блоков по 16 байт.
9
Здесь на место X может быть записана любая шестнадца-
теричная цифра от 0 до F. Размер памяти 16 байт
называется параграфом. Поэтому сегменты начинаются
на границах параграфов.
Начальный адрес сегмента хранится в 16-разрядном
сегментном регистре, а обращение к байту или слову
внутри сегмента осуществляется с использованием 16-
разрядного смещения. Большинство команд МП опери-
рует только 16-разрядными смещениями, а сегментные
адреса находятся в одном из четырех регистров: CS —
код (программа); DS — данные; SS—стек; ES — экст-
ракод (дополнительные данные). В состав блока регист-
ров общего назначения (РОН) входят четыре 16-разряд-
ных регистра (АХ, ВХ, СХ и DX), допускающих неза-
висимую адресацию старших (Н) и младших (L) байтов.
Все РОН участвуют в выполнении арифметических
и логических операций, представляя операнды и фикси-
руя результат. Наряду с этим имеется множество команд,
которые специализируют некоторые РОН так, как это
показано на рис. 1.1. Четыре 16-разрядных указательных
и индексных регистра (SP, BP, SI, DI) предназначены
для хранения внутрисегментных смещений. Эти же регист-
ры могут участвовать в выполнении арифметических
и логических операций над двухбайтными словами. Ре-
гистры (SP) стека и ВР (базы) используются для доступа
к данным в текущем сегменте стека, a SI и DI — в текущем
сегменте данных. Регистр адреса (счетчик адреса) IP при-
меняется для выбора команд программы в текущем сег-
менте кода CS. Регистр признаков (флагов) предназна-
чен для хранения данных о различных ситуациях, возни-
кающих в программе.
Важным компонентом ПЭВМ является оперативная
память (ОП). Логически она организована в виде после-
довательности байтов с адресами от 0 до 2'1—1;, где п —
число разрядов адреса. Рис. 1.2 показывает организацию
адресного пространства памяти.
Для выбора данных в сегменте DS используются
4 регистра: ВХ, BP, SI и DI. Большинство команд МП
позволяет брать в качестве операнда содержимое регист-
ра либо ячейки ОП. В первом случае достаточно задать
только имя регистра, например АХ или CL. Для указания
ячейки памяти существует несколько различных способов
адресации, которые подробно будут рассмотрены в гл. 8.
Экстракодовый сегмент используется для передачи
данных между ячейками ОП, не попадающими в непре-
10
Рис. 1.2. Организация адресного пространства памяти
рывную область объемом 64 К байт. Например, если
необходимо переслать данные из байта с номером 100000
в байт с номером 200000, то это невозможно сделать
в пределах одного сегмента данных (DS). Тогда первый
байт включается в сегмент DS, а второй — в сегмент ES,
и выполняются необходимые операции.
Для указания местоположения команды в ОП исполь-
зуется пара регистров: CS и IP. Это записывается как CS:
IP (по аналогии задаются 32-разрядные значения для
других пар регистров). Для адресации следующей коман-
ды в программе применяются три способа:
1) по мере загрузки и выполнения команды значение
регистра IP увеличивается на ее длину (естественная
последовательность выполнения команд друг за другом);
2) вводится команда перехода внутри текущего сег-
мента CS (NEAR переход), которая изменяет значение
только регистра IP;
3) вводится команда перехода между сегментами
(FAR переход), которая изменяет значения как регист-
ра IP, так и регистра CS. При этом появляется возмож-
ность реализовать переходы на расстояние более 64 К
байт и выполнять программу, находящуюся в любом
месте адресного пространства памяти.
Пара регистров SS:SP всегда указывает на текущую
вершину стека (рис. 1.3). Данные в эту область ОП
СТАРШИЕ АДРЕСА ОП
SP
УВЕЛИЧЕНИЕ
СТЕКА
[УМЕНЬШЕНИЕ
ЗНАЧЕНИЯ SP)
ОБЛАСТЬ
СТЕКА
УМЕНЬШЕНИЕ
СТЕКА
[УВЕЛИЧЕНИЕ
ЗНАЧЕНИЯ SP)
S3
МЛАДШИЕ АДРЕСА ОП
Рис. 1.3. Организация стековой памяти
помещаются только в виде слов (2 байта). При занесении
слова в стек значение SP уменьшается на два, а при его
извлечении увеличивается на два (см. рис. 1.3). Другими
словами, стек растет в направлении к началу ОП. Если
данные помещаются в стек, то сначала изменяется содер-
жимое SP, а затем осуществляется запись информации
в ОП. Например, если программа установила SS на
600016, a SP на Oie, то первое слово попадет в байты
с адресами 6000:FFFF (здесь FFFFi6= OOOOie —OOOlie)
12
и 6000:FFFE (здесь FFFEi6= FFFFi6—OOOlie). Пред-
положим, что очередное слово размещено по адресам:
6000:0001 и 6000:0000. Запись еще одного слова при-
ведет к тому, что оно попадет в байты 6000: FFFF и 6000:
FFFE. В результате старая информация будет испорчена.
К еще худшим последствиям может привести перепол-
нение стека при его объеме меньше 64К байт. Найти
подобные ошибки трудно. Поэтому для стековой области
следует выделять достаточный объем памяти.
Для адресации данных в стеке наряду с регистром SP
можно работать с регистром ВР, который при доступе
к данным использует по умолчанию регистр SS. Обра-
щаясь к ВР, программа может рассматривать его как
базовый регистр в сегменте стека и находить данные
как смещения относительно этого регистра (соответст-
вующие примеры даны в гл. 8).
Опишем теперь структуру регистра признаков. Его
младший байт устанавливается арифметическими или ло-
гическими операциями МП. Признак SF имеет единичное
значение при отрицательном и нулевое при положительном
результате. Флаг ZF принимает значение 0 при нулевом
результате последней операции. PF устанавливается в еди-
ницу, если результат последней операции имеет четное
число единиц. Признак CF используется для различных
целей. Он устанавливается в единицу при сложении
16-битовых чисел в случае возникновения переноса и при
вычитании аналогичных чисел для указания необходи-
мости заема. Программа может использовать этот флаг
для определения соотношения двух чисел А и В. Если
выполняется операция А —В и CF= 1, то В>А (если
CF = 0, то А В). Признак AF позволяет МП выполнять
операции десятичной арифметики, когда данные хранятся
в двоично-десятичном коде. Флаг переполнения OF пока-
зывает, что результат арифметической операции вышел за
пределы диапазона чисел, представленных в дополнитель-
ном коде. Остальные признаки регистра устанавливаются
программистом.
После того как TF станет равным 1, при завершении
каждой команды возникает прерывание работы МП: это
помогает отлаживать различные программы. Если IF =
= 0, никакие внешние прерывания (за исключением не-
маскируемых) не смогут возникнуть. Если IF= 1, МП
будет реагировать на внешние прерывания. Признак DF
используется при обработке блоков данных. Для указания
объектов (байтов или слов) в каждом блоке применяются
13
индексные регистры. После обработки объекта МП изме-
няет содержимое индексных регистров для выбора следую-
щего элемента данных. Если DF=0, команды, работаю-
щие с блоками, увеличивают содержимое индексных ре-
гистров; при DF = I содержимое этих регистров умень-
шается.
К другим ресурсам машины, на которые можно воз-
действовать программами пользователя, относятся таймер
(для отсчета временных интервалов), блок управления
динамиком (для генерации звуковых сигналов), каналы
ввода-вывода (для организации связи с периферийным
оборудованием) и т. п. Управление дисплеем и накопи-
телями на дисках осуществляется с помощью специаль-
ных блоков, называемых периферийными адаптерами. Они
имеют собственные программно-доступные ресурсы, кото-
рые будут рассмотрены далее.
Главным программным средством ПЭВМ является
операционная система. Она служит как бы оболочкой
вокруг различного рода устройств и позволяет отделить
остальные классы программ от непосредственного взаимо-
действия с аппаратурой. В ПЭВМ есть программа, реали-
зованная в постоянном запоминающем устройстве (ПЗУ)
системного блока, которая может быть отнесена как
к аппаратным средствам, так и к компонентам ОС,—
это базовая система ввода-вывода (BIOS). На ПЭВМ
могут поставляться различные ОС, но все они используют
один и тот же модуль BIOS, который выполняет инициали-
зацию и проверку аппаратных средств при включении
машины, обработку прерываний нижнего уровня, чтение
первой программы ОС (загрузчика) из первого сектора
системного диска в ОП.
1.3. РАСПРЕДЕЛЕНИЕ ОПЕРАТИВНОЙ ПАМЯТИ
Материал этого параграфа предполагает наличие у читателя опре-
деленных знаний об ОС ПЭВМ. В противном случае следует предва-
рительно ознакомиться с гл. 3
В табл. 1.2 приведена карта распределения ОП.
Объекты, перечисленные в последнем столбце табл. 1.2,
размещаются в памяти друг за другом от младших адре-
сов к старшим. Первые 1024 байта ОП отведены для
векторов прерываний. Каждый из них задает адрес сег-
мента и смещение для программы обработки прерывания.
Один вектор занимает 4 байта: 2 байта со старшими
адресами определяют сегмент, а 2 байта с младшими
14
Таблица 1.2
Границы уч асткоа ОП, К байт Сегментный адрес сме- щение Содержимое ОП
0 0000:0000 Векторы прерываний: 256 четырехбайтных ад-
ресов
1 0040:0000 Область данных BIOS (см табл. 1.3)
1,25 0050:0000 Область данных ОС
ХХХХ:ОООО Модуль ОС IBMBJO.COM
ХХХХ:0000 Модуль ОС JBMDOS.COM
XXXX.-0000 Буферная область и область данных ОС
ХХХХ:0000 Резидентная часть командного процессора
COMMAND.COM (приблизительно 4 К байт)
ХХХХ:0000 Резидентные утилиты
XXXX.-0000 Область памяти для прикладных программ
типа СОМ и EXE
ХХХХ:0000 Стек для программ
ХХХХ:ОООО Нерезидентная часть командного процессора
COMMAND. СОМ
640 А000.0000 Экранная память для адаптера EGA
704 В000:0000 Экранная память монохромного дисплея
736 768 В800:0000 сооо-.оооо Экранная память для адаптера CGA Начало области ПЗУ
984 1016 F 600:0000 FE00:0000 Интерпретатор языка БЕЙСИК в Модуль BIOS в ПЗУ ПЗУ
адресами — смещение. Рассмотрим, например, прерыва-
ние 22 (161б). Для него вектор будет располагаться
по адресам: 88, 89, 90, 91 (58i6, 59,6, 5Aie, 5Bie). Если
там будет записано в шестнадцатеричном коде: 2Е-F8 00
F0, это соответствует сегменту F000 и смещению F82E.
Переменные BIOS и ОС используются различными
системными программами. В табл. 1.3 смещение взято
относительно сегмента с адресом 0, хотя в табл. 1.2 адрес
сегмента равен 0040. Здесь следует учесть, что физические
адреса вида 0040:0002 и 0:0402 указывают на один
и тот же байт памяти.
Отметим еще несколько важных ячеек ОП. По адресу
F000:FFF5 записывается номер версии BIOS, например
12/05/86. Здесь используются 8 байт в ASCII-коде.
По адресу F000:FFFE записывается код типа ПЭВМ:
15
Таблица 1.3
Адрес Количест- во байтов Содержимое ОП
I 2 3
0:0400 2 Адрес порта СОМ1
0:0402 2 Адрес порта COM2
0:0404 2 Адрес порта COM3
0:0406 2 Адрес порта COM4
0:0408 2 Адрес порта LPT1
0;040А 2 Адрес порта LPT2
0-.040С 2 Адрес порта LPT3
0:040Е 2 Адрес порта LPT4
0:0410 2 Установленное оборудование
0:0412 1 Ошибки связи для клавиатуры, оформленной в виде устройства, взаимодействующего с ПЭВМ посредством инфракрасного излучателя
0:0413 2 Общий объем ОП, К байт
0:0415 2 Рабочая область для тестов пользователя
0:0417 2 Состояния некоторых клавиш (см. § 2.1)
0:0419 1 Используется для ввода ASCll-кода символа с помощью клавиши ДОП (АН) и цифровой кла- виатуры. Когда клавиша ДОП отпускается, накоп- ленное значение пересылается в буфер клавиатуры
0:041 А 2 Адрес начала буфера клавиатуры
0:041 С 2 Адрес конца буфера клавиатуры
0:041Е 32 Буфер клавиатуры
0:043Е 1 Требуется рекалибрация накопителя на гиб- ких магнитных дисках (НГМД) (бит 0—А, бит 1—В и т. п.)
0:043F 1 Мотор дисковода включен (бит 0 — А, бит 1 — В ит. п.)
0:0440 1 Время до выключения мотора
0:0441 1 Код ошибки дисковода
0:0442 7 Состояние контроллера НГМД
0:0449 1 Текущий активный режим работы дисплея
0:044А 2 Ширина экрана дисплея, знакомест
0:044С 2 Объем экранной памяти, байт
0:044Е 2 Смещение от начала экранной об^дсти активной видеостраницы
0:0450 16 Местоположение курсора (8 двухбайтных слов, в которых младший байт — номер колонки, стар- ший — номер строки)
0:0460 2 Размер курсора (старший байт — начальная, младший — конечная линия)
0:0462 1 Номер активной видеостраницы
0:0463 2 Адрес порта видеоконтроллера адаптера CGA 6845
0:0465 1 Текущее значение видеорежима (CRT MODE) контроллера 6845
0:0466 1 Текущее значение палитры (CRT PALETTE) контроллера 6845
0:0467 5 Область данных POST (самопроверка при за- грузке)
16
Окончание табл. 1.3
з
0:046С
0:0470
0:0471
0:0472
0:0474
(0475)
0:0478
0:047С
0:0480
0:0482
0:0484
0:0485
0:0487
0:0488
0:0490
0:0491
0:0492
0:0493
0:0494
0:0495
0:0496
0:0497
0:0498
0:049С
0:04А0
0:04А1
0:04А8
0:04F0
0:0500
0:0504
0:0510
0:0530
4 Счетчик импульсов таймера (через каждые 55 мс
с момента сброса)
1 Переполнение таймера
1 В бит 7 записывается единица при нажатии
клавиш УПР—СТОП (Ctrl—Break)
2 1234|6 означает, что выполняется перезагрузка
после нажатия клавиш УПР—ДОП — УДЛ
(Ctrl-Alt-Del)
4 Управляющая область твердого диска (АТ)
1 Число драйверов для твердого диска (АТ)
4 Значения времени вывода (time out) принтеров
4 Значения времени вывода (time out) коммуни-
кационного канала RS-232C
2 Начальный адрес смещения буфера клавиатуры
(АТ)
2 Конечный адрес смещения буфера клавиатуры
(АТ)
1 Число символьных строк экрана минус единица
(адаптер EGA)
2 Число байтов на символ (адаптер EGA)
1 Различная информация для адаптера EGA (ре-
жим, тип дисплея и т. п.)
1 Различная информация для адаптера EGA (ус-
тановка переключателей и т. п.)
1 Биты состояния диска 0 (используется для дисков
объемом 1,2 М байт) (АТ)
1 Биты состояния диска 1 (АТ)
1 Признак запуска для дисковода 0 (АТ)
1 Признак запуска для дисковода 1 (АТ)
1 Текущий номер цилиндра для дисковода 1 (АТ)
1 Текущий номер цилиндра для дисковода 2 (АТ)
1 В бите 4 записывается единица, если подклю-
чена клавиатура со 101 клавишей (АТ)
1 Признак подключения для светодиодного дисплея
(АТ)
4 Адрес признака ожидания пользователя (АТ)
4 Число микросекунд ожидания пользователя (АТ)
1 Признак активности ожидания (АТ)
7 Зарезервировано для сетевых адаптеров (АТ)
4 Адрес таблицы указателей для адаптера EGA
1016 Область связи (может использоваться приклад-
ными программами)
1 Статус печати экрана: 0 — печать завершена;
1 — печать активна; ff16 — ошибка при печати
1 Статус гибких дисков (если записана единица,
то диск А воспринимается как диск В)
11 is Используется интерпретатором БЕЙСИКа
3 ' Используется утилитой MODE
FF — IBM PC- FF — TRM РГ/YT- FD—PCjr- FF —
IBM PC/AT.
17
После раздела «Область данных ОС» (см. табл. 1.2)
идут программы операционной системы: модуль расшире-
ния базовой системы ввода-вывода IBMBIO.COM, модуль
обработки прерываний IBMDOS. СОМ и резидентная
часть командного процессора COMMAND. СОМ. Нерези-
дентная часть COMMAND. СОМ располагается по стар-
шим адресам ОП непосредственно перед экранной об-
ластью. Она может «затираться» прикладными програм-
мами и должна в этом случае «подгружаться» с систем-
ного диска в процессе работы ПЭВМ. После модулей ОС
размещаются резидентные утилиты и программы пользо-
вателя (см. табл. 1.2). Соответствующий раздел занимает
область до границы 640 К байт. Далее идет экранная
память, которая помещается на плате соответствующего
адаптера (в ПЭВМ ЕС 1840.05, ЕС 1841 адрес начала
экранной памяти В800:0000). Наконец, с адреса С000:
0000 идет область ПЗУ. Раздел С000:0000 — F600:0000
отведен для специализации ПЭВМ под конкретную пред-
метную область. Начиная с адреса F600:0000 в ПЗУ
может быть размещен интерпретатор БЕЙСИКа объемом
32 К байт. Последние 8 К байт, начиная с адреса FE00:
: 0000, занимает модуль BIOS. Области памяти, исполь-
зуемые для ПЭВМ семейства АТ, помечены символа-
ми (АТ).
1.4. КАНАЛЫ И ПОРТЫ ВВОДА-ВЫВОДА
Каналы ввода-вывода используются для подключе-
ния к ПЭВМ различных периферийных устройств (ПУ).
Различают параллельный и последовательный каналы.
Временная диаграмма работы параллельного канала по-
казана на рис. 1.4, а (рассматривается широко распрост-
раненный интерфейс Centronics). Сигналы BUSY и ASK
поступают от ПУ. Высокий уровень сигнала BUSY пока-
зывает, что ПУ не может принимать даййые. Низкий
уровень сигнала ASK означает, что данные были при-
няты и ПУ готово к приему следующей информации.
Импульс STROBE сопровождает данные от ПЭВМ (вы-
деляет интервал времени, когда их можно принимать);
его ширина должна быть не менее 0,5 мкс на приемном
выводе. ПУ вырабатывает еще один сигнал ERROR, когда
оно не готово к работе либо если произошла ошибка
в передаче данных. К параллельным каналам ПЭВМ
могут подключаться принтеры, графопостроители и другие
устройства.
18
s
СТАРТОВЫЙ БИТ БИТ ЧЕТНОСТИ
1.................. \
____Г
БИТЫ ДАННЫХ СТОП-БИТЫ
Рис. 1.4 Временные диаграммы работы каналов ввода-вывода
Временная диаграмма работы последовательного ка-
нала показана на рис. 1.4, б (рассматривается широко
распространенный интерфейс RS-232C). Информационная
посылка начинается со стартового бита. Затем идет опре-
деленное число (от 5 до 8) битов данных и бит четности.
Заканчивают посылку 1 или 2 стоп-бита. Передача может
осуществляться синхронно и асинхронно. Все параметры
обмена можно устанавливать программно либо с помощью
команд ОС. К последовательным каналам ПЭВМ могут
подключаться графопостроители, устройства съема коор-
динат, манипуляторы типа «мышь» и другое оборудо-
вание.
К портам относят совокупность средств, унифицирую-
щих и упрощающих способ взаимодействия микропроцес-
сора с внешней средой. Всем ресурсам ПЭВМ, кроме ОП,
таким, как клавиатура, дисковод, динамик и т. п., выде-
ляются свои порты (логические адреса ввода-вывода).
Так, прием кодов от клавиатуры осуществляется через
порт 96 (601б), управление динамиком —через порт 97
(611б) и т. п. В табл. 1.4 приведены номера портов для
других ресурсов ПЭВМ. Некоторые из них подробнее
будут рассмотрены далее. Ввиду небольших различий
отдельно указаны номера портов для ПЭВМ семейства
IBM PC/AT и IBM PC/XT.
Порты с номерами 0—FFie используются только сис-
темной платой. Номера 10016—3FF16 декодируются на ши-
19
Таблица 1.4
АТ PC/XT Назначение
ООО—01F 000—00F Порты контроллера прямого доступа в па- мять (8237А-5)
020— 03F 020—021 Порты контроллера прерываний (8259А)
040—05F 040—043 Порты таймера (8253-5) (АТ:8254.2)
— 060—063 Порты программируемого периферийного интерфейса (клавиатура, переключатели, таймер)
060— 06F — Порты контроллера клавиатуры
070—07F — Порты часов и памяти с батарейной под- питкой (CMOS-memory) Маска NMI (немаскируемых прерываний)
080 — Контрольная точка изготовителя для диаг- ностики
0,8 0 — 0,9 F 080—083 Порты регистра страниц контроллера пря- мого доступа в память
ОАО—0BF ОАО Маска NMI Порты второго контроллера прерываний (8259А) Порты второго контроллера прямого досту- па в память (8237А-5)
0С0—0DF —
0F0—OFF — Порты сопроцессора
170—177 — Порты второго твердого диска (винче- стера)
1F0—1F7 — Порты твердого диска (винчестера)
200—207 200—20F 210—217 Порты джойстика Порты блока расширения
278—27F 278—27F Порты второго параллельного принтера
2С0—2DF 2С0—2D Порты второго адаптера EGA
278— 2FF 278—2FF Порты второго асинхронного адаптера
300—31F 320—32F Порты платы прототипа Порты твердого диска
370—377 — Порты вторичного контроллера дискет
378—37F 378—37F Порты первого параллельного принтера
380— 38F 380—38F Порты контроллера синхронной связи
ЗАО—3AF ЗАО—ЗА9 Порты первого синхронизированного ка- нала
ЗВО—3BF ЗВО—3BF Порты монохромного адаптера (принте- ра 1) «.
ЗСО—3CF ЗСО—3CF Порты первого адаптера EGA
3D0—3DF 3D0—3DF Порты CGA и EGA
3F0—3F7 3F0—3F7 Порты контроллера дискет
3F8—3FF 3F8—3FF Порты первого асинхронного адаптера
не ввода-вывода для использования различными адапте-
рами. Порты с номерами 40016 и выше недоступны. Все
числа, записанные в столбцах АТ, PC/XT табл. 1.4,
шестнадцатеричные. В скобках указаны типы различных
контроллеров для оригинальных моделей ПЭВМ IBM
PC/XT и АТ.
20
Рассмотрим основные принципы работы с портами
ввода-вывода. Изложение будем вести с привязкой к ори-
гинальным моделям ПЭВМ IBM PC/XT, АТ, PS/2. Связь
с периферией обеспечивает микросхема параллельного
интерфейса Intel 8255. Заметим, что модель АТ не исполь-
зует ее и хранит сведения об оборудовании вместе с ин-
формацией о текущем времени в специальной микросхеме
(МС146818 фирмы Motorola) с независимым (батарей-
ным) питанием (CMOS-memory). Тем не менее модель АТ
использует те же самые адреса портов.
Микросхема 8255 содержит три однобайтных регистра,
которым соответствуют порты 60ie, 61ie и 62ie (см. табл.
1.4). Читать данные можно из всех регистров, а записы-
вать — только во второй из них. Охарактеризуем некото-
рые биты этих регистров, которые будут использованы
далее в примерах. Если бит 7 порта 61,6 установлен
в нуль, то биты 0—7 порта 60ie передают скэн-коды от
клавиатуры (см. об этом далее, в § 2.1). Запись единицы
в бит 7 порта 6116 подтверждает прием скэн-кода и раз-
решает его изменение. Бит 0 порта 61 ]6 управляет ка-
налом 2 (третьим счетчиком) таймера 8253 (порт 42.6).
Запись в него значения 0 задает режим непосредственно-
го управления динамиком с помощью бита 1 (при единице
в этом бите диффузор динамика втягивается, а при нуле
отпускается). Если в бите 0 единица, то динамиком
будет управлять третий счетчик таймера 8253. Сигналы
от него пропускаются, когда бит 1 установлен в единицу.
Остальные биты порта 6Ее предназначены для инициали-
зации и диагностики [3]. Биты порта 62i6 по-разному
интерпретируются для различных ПЭВМ. Они соответст-
вуют переключателям, задающим объем памяти, показы-
вают тип системной ошибки и т. п. Бит 5 этого порта
связан с выходом второго счетчика таймера 8253.
Модель АТ хранит информацию о конфигурации в так
называемой CMOS-memory (микросхема МС146818). Она
имеет 64 регистра с номерами от the до 3Fiе- Для того что-
бы прочитать значение из регистра с номером N, необхо-
димо сначала послать этот номер в порт 70,6, а затем
прочитать значение из порта 7 Ее. Укажем шестнадцате-
ричные (и в скобках десятичные) номера некоторых ре-
гистров и данные, которые в них записаны:
0 (0)—секунды;
1 (1) — сигнал по секундам;
2 (2)—минуты;
3 (3)—сигнал по минутам;
21
4 (4) — часы;
5 (5)—сигнал по часам;
6 (6) — день недели;
7 (7)— день месяца;
8 (8) — месяц;
9 (9) — год;
А (10)—регистр статуса А;
В (11)—регистр статуса В;
С (12) — регистр статуса С;
Д (13) —регистр статуса D;
10 (16) —тип накопителя на гибких магнитных дис-
ках (НГМД) (биты 7—4— первый накопитель, 3—0—
второй накопитель, 0000—отсутствие накопителя, 0001 —
двухсторонний накопитель с плотностью 48 дорожек на
дюйм, 0010— двухсторонний накопитель с плотностью 96
дорожек на дюйм);
12 (18)—тип фиксированного диска (биты 7—4—
первый диск, 3—0—второй);
14 (20)—установленное оборудование (биты 7—6:
00—один НГМД, 01—два НГМД; биты 5—4: 01—цвет-
ной дисплей 40X 25, 10—цветной дисплей 80X 25, 11 —
монохромный дисплей; биты 3—2 не используются; бит
1:1—есть сопроцессор, 0—нет; бит 0:1 — есть НГМД,
0— нет);
15 (21)—объем памяти на системной плате (младший
байт), К байт;
16 (22)—объем памяти на системной плате (старший
байт), К байт;
17 (23) —объем общей памяти (младший байт), К
байт;
18 (24) —объем общей памяти (старший байт), К
байт;
30 (48) — память сверх одного мегабайта (младший
байт);
31 (49) — память сверх одного мегабайта (старший
байт);
32 (50) —текущее столетие (например, 19-е).
Заметим, что для ПЭВМ семейства PS/2 имеются
отличия, например текущее столетие задается в регист-
ре 37 (55).
При достижении заданного времени может быть вы-
полнено аппаратное прерывание IRQ8 (только для моде-
ли АТ). Механизм прерываний будет рассмотрен в сле-
дующем параграфе. Например, если значения в регист-
рах 1, 3 и 5 совпадут с соответствующими значениями
22
в регистрах 0, 2 и 4, возникает аппаратный сигнал (IRQ8).
Рассмотрим теперь некоторые биты статусных ре-
гистров.
Регистр А: если бит 7 в единице, выполняется моди-
фикация времени.
Регистр В: если бит 6 в единице, разрешено перио-
дическое прерывание; если бит 5 в единице, разрешено
прерывание по совпадению значений в соответствующих
регистрах (0—1, 2—3, 4—5); если бит 4 в единице, раз-
решено прерывание конца модификации (IRQ8 после
каждого обновления значений регистров); если бит 2
в единице, время выдается в двоичной форме, в против-
ном случае — в двоично-десятичной; если бит 1 в единице,
время измеряется в интервале от 0 до 24 часов (при нуле —
от 0 до 12 часов); если бит 0 в единице, разрешено запо-
минание времени суток.
В качестве таймера в ПЭВМ используется микросхе-
ма Intel 8253 (8254 для АТ). Она имеет три однотипных
канала (с номерами 0—2), каждый из которых может
программироваться. Микросхема работает независимо от
процессора и позволяет выполнять функции часов реаль-
ного времени. Каждый канал состоит из трех регистров.
Первой группе соответствует порт 4016, второй — 41,6
и третьей — 42ie. Данные через порт засылаются в ре-
гистр ввода-вывода побайтно (сначал младший байт,
потом старший). Полученное число передается в шестнад-
цатиразрядный буферный регистр, который хранит его.
В заданные моменты времени копия полученного числа
посылается в шестнадцатиразрядный счетчик. При появле-
нии импульса на входе значение счетчика уменьшается
на единицу. При достижении нуля соответствующий канал
выдает выходной сигнал, и новая копия содержимого
буферного регистра пересылается в счетчик. Далее указан-
ные действия повторяются. Текущее значение каждого
счетчика можно прочитать в любой момент, не влияя на
счет.
Таймер получает прямоугольные импульсы с частотой
1,19318 МГц (1 193 180 импульсов в секунду). Канал 0
позволяет определять время суток. Он устанавливается
средствами BIOS так, что выдает импульсы примерно
через 55 мс (18,2 раза в секунду). Результаты подсчета
этих импульсов хранятся в области переменных BIOS
по адресу 0:046С (см. табл. 1.3). Канал 1 управляет
регенерацией памяти (его лучше не трогать). Канал 2 свя-
зан с динамиком (звук не возникнет до тех пор, пока не
23
реализованы рассмотренные выше установки для пор-
та 6116).
Каждый канал имеет две входные и одну выходную
линии. Выходная линия выводит импульсы, когда счетчик
переходит через нуль. На первую входную линию посту-
пают прямоугольные импульсы (с частотой 1,19318 МГц).
Вторая линия разрешает либо запрещает прохождение
этих импульсов. Для каналов 0 и 1 разрешение уста-
новлено постоянно, а для канала 2 оно управлется битом О
порта 6116 (см. об этом выше).
Порт 4316 связан с восьмиразрядным командным ре-
гистром микросхемы 8253. Его биты могут принимать
следующие значения: если бит 0 установлен в нуль, то
счет двоичный, в противном случае — двоично-десятич-
ный; биты 1—3—номер режима (ООО—0, 001 — 1, ХЮ—2,
XII—3, 100—4, 101—5, символом X помечены безразлич-
ные значения); биты 4—5—тип операции (00— передать
значение счетчика в буферный регистр, 01—загрузка
(запись) только младшего байта, 10— загрузка (запись)
только старшего байта, 11—загрузка (запись) сначала
младшего, потом старшего байта); биты 6—7 — номер ка-
нала (00—0, 01 — 1, 10—2).
Таймер может работать в шести различных режимах.
По умолчанию устанавливается режим 3 для всех каналов,
в котором половину периода выход канала имеет низкий
логический уровень и половину — высокий. Как только
буферный регистр получает число, он немедленно загру-
жает его в счетчик. Иногда применяют режим 0, вызы-
вающий прерывание по завершении счета. В этом режиме
таймер не работает непрерывно [3]. Он не начнет считать
до тех пор, пока в него не будет загружено число. В момент
достижения нуля возникнет прерывание IRQ0.
При работе с таймером программы после своего за-
вершения должны восстанавливать начальные значения
регистров.
Рассмотрим примеры программ, использующих описанные порты.
Для демонстрации операций низкого уровня наиболее удобным являет-
ся язык ассемблера. Однако различные операции, связанные с вводом
и выводом числовой и символьной информации, отвлекают от главной
цели (соответствующие фрагменты на языке ассемблера имеют до-
вольно большой объем). Учитывая это, в приведенных ниже программах
все, что не касается работы с портами, дано на языке СИ (ввод-вывод
и некоторые другие операции). Там, где необходимо показать конкрет-
ные правила работы с портами, включаются фрагменты на языке
ассемблера. Детали взаимодействия программ и операторы языков
программирования описаны в гл. 6, 8, 9. Здесь на них мы останавли-
ваться не будем. Все программы в книге снабжены содержательными
24
комментариями, описывающими каждое из выполняемых действий. Ис-
пользуются система программирования ТУРБО СИ (2.0) и макроас-
семблер (MASM 5.1).
В первом примере вводятся различные символы (язык СИ).
ASCII-код символа, умноженный на 100 (значение Ь), косвенно задает
частоту звучания. В программе на ассемблере выполняются такие
действия:
1) в регистр СХ заносится значение переменной Ь, полученной
из программы на языке СИ;
2) в порт 43|6 заносится управляющее слово В6]6 (101101 Юз) —
двоичный счет, режим 3, загрузка (запись) сначала младшего, потом-
старшего байта, канал 2;
3) в порт 42ie заносится значение частоты звучания;
4) в биты 0 и 1 порта 61ie записываются единицы;
5) выполняется цикл (65 535 раз), определяющий время звучания;
6) восстанавливается первоначальное значение порта 6116.
Тексты программ на языках СИ и ассемблера приведены ниже:
♦include rconio.h?
extern int nyasnl(int); /» обившие внешней функции •/
void uin()
( int b;
char c;
while((c=getch()I!=27) 1 /» условие завершив цша
в программы «/
Ь=с»100; /« установка требуемой частоты звучания
(ASCII-код введенного символа, ухно-
денный на 10») »/
шуаввЦЬ); ) /> вызов программы на ассемблере >/
1
.мот SHALL объявление халой модели
.CODE ; сегмент кода
PUBLIC jyasxl вуавв!, доступная нз другого языка
jyasal PROC начало тела программы
pnsh bp значение Ьр заносится в стех
nov bp,sp ; значение вр заносится в Ьр
bov ex,[bpt4] ; загрузка аргумента в сх
pop bp ; значение Ьр читается нз стека
; управление высотой звука
nov al,0B6B ; в al заносится управлявшее слово для таймера-счетчика
out 430,al ; управлявшее слово посылается в порт
ov ax,ex частота звучания будет равна 1.19 МГц/ex (заносится в ах)
out 420,al ; значение частоты пересылается в порт
bov al,ah ; (сначала младший байт, затем старший
out 420,al байт)
in al,610 читается байт из порта 610
bov ah,al ; нрочнтанный байт сохраняется в ah
or al,3 ; в два младших бита прочитанного байта записывается единицы
ont 610,al ; Новое значение пересылается в порт 610
snb ex,ox ; внполняется цикл, определявший время
tn: loop tn ; звучания с установленной частотой
bov al,ah ; сохраненный ранее байт заносится в al
25
ont 610,al ; восстанавливается нервоначальное
; значение порта 610
ret ; возврат из ассемблерной програнмн
jyasil EKDP : конец тела программа
И»
После запуска программы на выполнение нажатие любой клавиши
вызывает звук определеной частоты. Нажатие клавиши КЛЮЧ (ESC)
завершает программу.
Следующая программа показывает выполнение таких действий:
1) изменение интервала отсчета времени. По умолчанию он равен
1193180/6553518.2 импульса в секунду. Если в канал 0 (порт 40|6)
занести другое число, например N, интервал отсчета изменится и станет
равным 1193180/N (если занести 0, то после вычитания единицы он
сразу же превратится в число 65535, т. е. N=0 и N = 65535—это
практически одно и то же). Заметим, что перед обращением к дискам
необходимо восстанавливать старое значение, в противном случае будет
ошибка (канал 0 используется для некоторых дисковых операций);
2) установка режима непосредственного управления динамиком (за-
пись нуля в младший бит порта 61 к,;. Изменять разрешается только
нужные биты, а остальные трогать нельзя (операция and al, OfeH) ;
3) непосредственное управление динамиком с помощью бита 1 пор-
та 6116;
4) обеспечение программной задержки. При этом считывается те-
кущее значение счетчика из ячейки BIOS 0:046С и ожидается, когда
оно увеличится на единицу. Перестраивая канал 0 таймера, в про-
грамме можно регулировать эту задержку. По окончании работы про-
граммы восстанавливается первоначальная настройка канала 0 таймера.
Тексты программ на языках СИ и ассемблера приведены ниже:
tinclnde tstdio.h)
extern int nyas»2(int,int); /> объявление внемнеа функции »/
void lain()
{ unsigned int a,b;
float f;
pnts("Время задеряян?");
scant("Id",4a); /» ввод значения, яоторое будет попа-
дать в счетчик 0 таймера */
if(a != 0) ( f = 1193180./(float)a;
printf("Введенное времп задерхкн Xf as\n", 1000./f); )
pnts("Время звучания?");
scant("Id",4b); /» ввод значения, яоторое будет опре-
делять число циклов ввяпчення н
выклвчення динамика »/
iyas»2(a,Ь); /* вызов програнмн на ассембхере »/
1
.MODEL SHALL , объявление малой модели
.CODE ; сегмент кода
PUBLIC jyasi2 ; вуааа2, доступная нз другого языка
jyasi2 PROC ; начало тела програнмн
; чтение значеняй переданных аргументов
; из программы на язнке СК
push bp ; значение bp заносится в стек
мот hp,sp ; значение sp заносится в Ьр
iov Ьх,[Ьрь4] ; чтение нз стека значения первого пе-
; реданного аргумента в списке аргумен-
; тов СИ-функцин (в примере а)
26
»ov сх,(Ьр<6] ; чтение хз стека значенпп второго пе- реданного аргумента (в примере Ь)
Pop bp ; значение Ьр читается нз стека
; изменение интервала отсчета времен! (по умолчаний он ; равен приблизительно 55 мс (1/18.2 с)
bov al,368 ; установка заданного рехнма (внбор счетчика 0, загрузка и запись сначала нхадяего, а затем стархего байта
oat <30,al переенлка значения al в управлявший норт таймера
lev ax,bx ; > пересадка в ах нового значения счет- чика 0 таймера, полученного из прог- раххн на язнке СИ (значение Ьх)
ont <08,al ; нереенлка в счетчик 0 мяадмего байта
bov al,ab ; теперь в al стармнй байт
ont <08,al ; переенлка в счетчик 0 стархего байта
; установка рехяма непосредственного управления динамиком
in al,618 ; чтение в al байта нз порта 618
and al.OfeB ; запись нуля в младянй бит прочитанного байта
ont 618,al ; внвод измененного байта в порт 618
; непосредственное управление динамиком
начахо цикла
or al,2 ; запись еднннцн во второй бит байта в al
ont 61H,al ; внвод байта нз al в порт 618
mov bx,0 ; запись нуля в регистр Ьх
bov es.hx ; запись нуля в регистр ей
bov dx,es:{46cH] ; запись в dx текущего значения вре- ; меня в заданиях единицах
add dx,l ; увелнченне значения в dx на единицу
rl: hov hx,es:(46cH] ; этот фрагмент будет внполняться
cap bx,dx ; до тех пор, пока текуяее время
jne rl ; не увеличится на значение в dx
and al,Ofd0 ; запись нуля во второй бит байта в al
out 6IB,AL ; внвод байта яз al в порт 618
bov hi,0 ; следущне 1 строк расснатрн-
bov es.bx ; вались вине. Они обеспечивали
bov dx,es:[46cH] ; задерхку на единицу врененн
add dx,l ; (по умолчания» на 55 нс), В
r2i bov hx,es:[46cH] ; примере зто время задается
свр bx,dx jne r2 ; нз программы на язнке СИ
loop wwm ; конец цикла
; восстановление интервала отсчета времени, заданного i по унолчаннв (55 мс)
bov al,36В ; следующие 7 строк пояснялись
out 43В,а1 bov ах,65535 out 40В,al bov al,ah ; вше
out 40B,al ret ; возврат нз ассемблерной программы
_Byas»2 SHOP ; конец тела программы
END
Не следует задавать значения, меньшие 100—150, в канал
мера, поскольку это связано с увеличением частоты обращения к
ратному прерыванию 1RQ0.
0 тай-
аппа-
27
Последняя программа демонстрирует работу с микросхемой
МС146818 (CMOS-mernory). Она написана на языке СИ и предназна-
чена только для ПЭВМ семейств АТ,PS/2:
tinciude <stdio.h>
finclude <dos,h>
void >iain()
( int nreg; /» nreg - номер регистра HC146818 »/
outportbjOxTfl,41;
printf("Часы: tx\n*,inportb(0x71));
oulportb(0i70,2);
pr in tf("Кинуты: Xx\n”,inportb(0x71));
ontportbf0x70,0);
printf("Секунды- Ix\n',inportb(0x71)|;
putsfJxaxHte номер регистра");
scant("%d".inreg);
outportb(0x70,nreg);
printf("Значение: Ix\n",inportb(0x71)I;
)
Программа выдает текущее время и позволяет прочитать содержи-
мое любого из 64 регистров по его двоичному номеру.
На этом мы закончим предварительное знакомство
с портами ввода-вывода.
1.5. ПРЕРЫВАНИЯ
Прерывания позволяют вызывать и выполнять заранее
подготовленные программы для обработки некоторой си-
туации. Большинство из них входит в состав ОС. Разли-
чают аппаратные и программные прерывания. Аппаратные
прерывания вызываются сигналами аппаратуры, например
от таймера 8253. В это время процессор приостанавливает
работу, выполняет действия в соответствии с возникшей
ситуацией и продолжает решение прерванной задачи. Для
того чтобы вернуться в нужное место, его адрес (CS: IP)
вместе с регистром признаков (флагов) сохраняются в сте-
ке. Далее в (CS:IP) загружается адрес точки входа
в программу обработки прерывания, которой передается
управление. Последней инструкцией такой программы
является IRET (возвращение старых значений CS: IP и ре-
гистра признаков). Программные прерывания иниции-
руются программами и предназначены для выполнения
определенного вида работ.
Адрес точки входа в программу обработки прерывания
называют вектором. Каждый вектор имеет длину 4 байта.
Для хранения векторов выделены первые 1024 байта ОП.
Остановимся на механизме аппаратных прерываний.
Для их обслуживания используется микросхема Intel
8259, имеющая 8 уровней приоритетов от 0 до 7 (в ПЭВМ
28
семейства IBM PC нулю соответствует высший, а 7—
низший приоритеты). Обращения к ним обозначаются
через IRQO,..., IRQ7. ПЭВМ IBM PC/XT имеет один
контроллер 8259, а АТ — два (у АТ уровни обозначаются
IRQO,..., IRQ 15). Прерываниям IRQO,..., IRQ7 соответст-
вуют векторы от 816 до F16, прерываниям IRQ8,..., IRQ15
для АТ — векторы от 70!6 до 77|6. Входы контроллеров
8259 имеют следующее назначение: IRQO — сигнал от
таймера; IRQ1 — сигнал от клавиатуры; IRQ2 — сигнал
от второго контроллера 8259 для AT (IRQ8 — прерывания
от микросхемы МС146818 (см. выше); IRQ9 — програм-
мно переводится в IRQ2; IRQ10— резерв; IRQ11 — ре-
зерв; IRQ12 — резерв; IRQ13 — сигнал от сопроцессора;
IRQ14 — сигнал от контроллера винчестера; IRQ15 —
резерв); IRQ3 — сигнал от первого коммуникационного
адаптера СОМ1 (от второго адаптера для AT); IRQ4 —
сигнал от второго коммуникационного адаптера COM2
(от первого адаптера для АТ); IRQ5 — сигнал от контрол-
лера винчестера (от второго принтера LPT2 для АТ);
IRQ6 — сигнал от контроллера НГМД; IRQ7 — сигнал
от контроллера первого принтера (LPT1).
Микросхема 8259 содержит три однобайтных регистра,
которые связаны с линиями аппаратных прерываний. При
наличии запроса на прерывание устанавливается в едини-
цу соответствующий бит в регистре IRR. Биты регистра
обслуживания ISR показывают, какое прерывание обра-
батывается (если бит п в единице, то обрабатывается
прерывание п). Регистр маски (IMR) позволяет уста-
новить, какие прерывания в данный момент времени разре-
шены. Этому регистру соответствует порт 21,6— для пер-
вой микросхемы контроллера 8259 и АПе—для второй.
Чтобы очистить регистр обслуживания, необходимо по-
слать в порт 20е значение 20ю (одинаковые числа —
просто случайное совпадение).
Выполнение прерывания зависит от значения флага
IF (бит 9) в регистре признаков (см. рис. 1.1). Если он
в единице, возможны все прерывания, которые разрешает
маска (регистр IMR); если он в нуле, все аппаратные
прерывания запрещены. Для маскирования некоторых
прерываний нужно просто послать соответствующий код
в порт 21|6 или 1А16-
29
1.6. СИСТЕМНЫЕ РЕСУРСЫ
Рассмотрение системных ресурсов начнем с опреде-
ления типа ПЭВМ семейства IBM/PC. Для этого необхо-
димо прочитать байт оперативной памяти по адресу
FFFFEie (или, что то же самое, FEOO.'IFFE). Интер-
претация полученных значений рассмотрена в § 1.3.
Установленное оборудование можно определить, про-
читав значение переменной BIOS по адресу 0:0410 (см:
табл. 1.3); значения ее битов такие: если бит 0 в единице,
присутствует НГМД; если бит 1 в единице, есть сопро-
цессор (XT, АТ); биты 2—3 задают базовую память
(в АТ не используются); биты 4—5 задают активный
видеоадаптер (11—монохромный, 10—цветной 80X25
знаков, 01—цветной 40X 25); биты 6—7 задают число
дисководов (00—1, 01—2, 10—3, 11—4); бит 8 не исполь-
зуется для моделей PC, XT, АТ; биты 9—11 задают число
коммуникационных адаптеров от 0 (000) до 7 (111);
если бит 12 в единице, есть игровой адаптер; бит 13 не ис-
пользуется для моделей PC, XT, АТ; биты 14—15 задают
число установленных принтеров от 0 (00) до 3 (11).
Приведенная ниже программа на языке СИ позволяет узнать тип
ПЭВМ, определить ее системные ресурсы, включая объем ОП (послед-
ний читается по адресу 0:0413; см. табл, 1.3).
iinclnde <stdio.b>
linclnde <dss.h>
void iaiii{)
( int b;
b = peek(0,0x(19);
print!C\n\nCJOBO no адрес? 0:0x410 - Ix\n',b);
s«itcb(peekb(OxFKOO,txlFFS)l (
case OxFF; puts(45M - IBH PC'); break;
case OxFE: putsfHOBK - IBM PC/XT'); break;
case OxFD: puts("H3BX - PCjr'); break;
case OxFC: pnts(43BI - IBH PC/AT"); break; }
if(b 4 1) { pntsfMKJ присутствуй');
print!('Количество ИГМД - Jd\n',((b 4 OxcO)>>6)+1);
else potsIlPKI отсутствуют');
i!(h 4 2) putsj'Conpoiieccop есть'1;
else pnts('Сопроцессора нет'1;
s»itcb((b 4 Ox30)>>4) {
case 1: рпЬйСЦветной видеоадаптер (40x25)break;
case 2: рпЬвСОветной видеоадаптер (89x25)'); break;
case 3: puts('Конохронннн видеоадаптер*); break; )
print!("Число гоннуннгацноннп! адаптеров - Id\n',
(Ь 4 OxeOO)>>9);
if(h 4 9x1000) pnts("Есть игровой адаптер');
else puts('Вет игрового адаптера");
print!!"Число установленных принтеров - Xd\n',
(Ь 4 0хс000)>>14);
print!('Объем оперативной памяти - id К байт\п‘,
реек(О,0x413)И);
1
30
После запуска этой программы на выполнение соответствующая
информация с необходимыми текстовыми пояснениями выводится на
экран дисплея.
В ПЭВМ семейства IBM PC, работающей под управ-
лением ОС MS-DOS (по крайней мере до версии 3.30),
объем доступной для программ пользователя ОП ограни-
чен величиной 640 К байт. Однако в ПЭВМ может быть
установлена дополнительная память типа Extended или
Expanded.
Память типа Extended применяется только в ПЭВМ
семейств АТ и PS/2. Она занимает физическое адресное
пространство за пределами 1 М байта. В большинстве
случаев память этого типа используют для организации
виртуальных дисков с быстрым доступом. Определить
ее объем для конкретной ПЭВМ можно путем обращения
к регистрам 17,6 и 18t6 CMOS-memory (см. § 1.4).
Память типа Expanded использует специальную сов-
местимую плату и программный драйвер для осуществле-
ния страничной организации. Такие платы создают 4 шест-
надцатикилобайтные страницы (общий объем 64 К байт).
Перемещение страниц осуществляется из памяти за пре-
делами адресного пространства объемом 640 К байт.
При этом суммарный объем памяти может достигать
8 М байт. Ее используют для различных целей: органи-
зации виртуальных дисков, хранения данных, страниц
кода программы и т, п.
Память типа Expanded управляется драйвером с име-
нем устройства EMSXXXX0. Когда этот драйвер уста-
навливается, он формирует вектор прерывания с номером
6716, указывающий на заголовок устройства. Чтобы про-
верить его наличие, необходимо использовать смещение
А|6 от вектора 67,в (от адреса 0:019С). Там должно
быть слово EMSXXXX0.
2. ПЕРИФЕРИЙНЫЕ УСТРОЙСТВА ПЭВМ
2.1. КЛАВИАТУРА
Клавиатура является главным средством ввода инфор-
мации в ПЭВМ. Знание ее особенностей необходимо для
работы с машиной. В разных клавиатурах ПЭВМ разли-
чают следующие клавиши:
1) алфавитно-цифровые и знаковые: с символами
A,...,Z, a,...,z, А,...,Я, а.я, 0.9, + , —, *, /, &, ], ;, \, ?,
!, ., =Й=, и т- п-> а также специальные; Esc (Ключ), Tab
(=₽*), Enter (Ввод), Back Sp (-<-);
2) функциональные: Fl,..., F12 (Ф1,...,Ф12) (в ПЭВМ
ЕС 1840, ЕС 1841—Ф1,...,Ф10);
3) служебные для управления перемещением курсо-
ра и редактированием: Up (f), Down ().), Left (-<-),
Right (->), Home (\), End (KOH), Ins (BCT), PgUp (Й ),
PgDn (ф), Del (УДЛ);
4) служебные для смены регистров и модификации
кодов других клавиш: Alt (ДОП), Ctrl (УПР), Shift (ф);
5) служебные для фиксации регистров: Caps-Lock
(ФПБ), Scroll-Lock (ФСД), Num-Lock (ЦИФ);
6) вспомогательные: Prt-Sc (ПЕЧ), Sys-Rq (для АТ).
Различают три уровня представления и обработки
сигналов от клавиатуры — физический^; логический и
функциональный.
На физическом уровне анализируются сигналы, посту-
пающие в системный блок при нажатии и отпускании
клавиши. Например, клавиатура ПЭВМ семейства
IBM/PC представляет собой небольшой самостоятельный
компьютер. В ней размещается свой микропроцессор
Intel 8048, который следит за нажатиями клавиш и пере-
дает их состояние в МП. В основе кодирования переда-
ваемых в системный блок сигналов лежит обычная нуме-
рация клавиш. При нажатии любой из них в системный
блок посылается код, соответствующий ее порядковому
32
номеру — скэн-код. При отпускании клавиши во всех
ПЭВМ, кроме АТ, тоже генерируется ее номер, увели-
ченный на 128 (дополнительный скэн-код). Для модели
АТ код отпускания состоит из двух байтов: сначала
FO|6, а затем скэн-код. Микросхема 8048 позволяет буфе-
ризировать до 20 нажатий, если центральный процессор
не может принять соответствующие коды. При нажатии
клавиши дольше чем на 0,5 с автоматически генерируется
последовательность ее основных скэн-кодов с частотой
10 раз в секунду. Это имитирует серию очень быстрых
нажатий.
Логический уровень поддерживается базовой системой
ввода-вывода (BIOS) через прерывание 9. После нажатия
либо отпускания клавиши процессор клавиатуры записы-
вает ее скэн-код или дополнительный скэн-код в порт
6016 и посылает запрос на аппаратное прерывание (вход
IRQ1 контроллера 8259). Далее вызывается служебная
процедура BIOS (программа обработки прерывания)
и выполняются такие действия:
1) читается скэн-код (дополнительный скэн-код) из
порта 6016’,
2) выдается сигнал, подтверждающий прием кода
(сначала единица в бит 7 порта 61ie и затем сразу же
нуль в бит 7 порта бВе);
3) проверяется, не изменяет ли нажатая клавиша
биты статуса по адресу 1047 (417ie) и 1048 (418ie). Байты
417(б и 418|б уже упоминались в области переменных
BIOS (см. табл. 1.3). Их назначение будет рассмотрено
далее. Если биты статуса должны быть изменены, выпол-
няются соответствующие действия;
4) проверяется, есть ли место в' буфере клавиатуры,
который расположен по адресам 41Е16—43D16 (см. табл.
1.3). О нем мы также будем говорить далее. Если место
есть, скэн-код преобразуется в специальный двухбайтный
код и помещается в буфер. При отсутствии места вводимые
с клавиатуры символы отбрасываются и выдается звуко-
вой сигнал;
5) осуществляется выход из программы обработки
прерывания.
Младший из двух байтов, полученных в результате
преобразования, для клавиш первой группы содержит
ASCII-код, соответствующий изображенному на клавише
знаку. В старшем байте записан исходный скэн-код нажа-
той клавиши. Если в первом байте записан нуль, соот-
ветствующий код называют расширенным ASCII-кодом.
2 Скляров В А.
33
В этом случае старший байт содержит скэн-код нажатой
клавиши или он соответствует определенной комбинации
одновременно нажатых клавиш. Это позволяет проверить
тот факт, что нажатая в данный момент клавиша не от-
носится к первой группе. Информация о состоянии кла-
виш Ins, Caps-Lock, Num-Lock, Scroll-Lock, Alt, Ctrl,
Shift (левая и правая клавиши по отдельности), Ins
хранится в байтах ОЗУ с адресами 1047 (417,6) и 1048
(418|б). Она позволяет определить, какие действия с кла-
виатурой произведены (нажата алфавитно-цифровая
клавиша, специальная либо использована комбинация
клавиш). Предположим, что биты пронумерованы в байтах
с адресами 41716, 418,6 от 7 до 0 (в направлении от стар-
ших разрядов к младшим). Тогда для байта с адресом
417|6бит7 устанавливается, когда включен режим вставки
(INS), бит 6 — при включении режима прописных букв
(Caps-Lock), бит 5—при выборе режима малой цифро-
вой клавиатуры (Num-Lock), бит 4—в режиме ФСД
(Scroll-Lock), бит 3—при нажатии клавиши ДОП (Alt),
бит 2—при нажатии клавиши УПР (Ctrl), бит 1—при
нажатии клавиши смещения слева (Shift слева), бит 0—
при нажатии клавиши смещения справа (Shift справа).
Для байта 418,6 биты 7, 6, 5, 4 устанавливаются, когда
нажаты и удерживаются в нажатом состоянии соответст-
венно клавиши INS, Caps-Lock, Num-Lock, Scroll-Lock.
Бит 3 устанавливается при включении режима УПР —
ЦИФ (Ctrl — Num-Lock).
Рассмотрим организацию буфера клавиатуры. Смеще-
ния его начала и конца в области переменных BIOS
записаны в ячейках по адресам 41А,е и 41С,е. Каждое
смещение задается двухбайтным словом, хотя использует-
ся только младший байт, возможные значения которого —
от 30 (1Е,б) до 60 (ЗС,б); отсчет ведется от адреса 400,6-
Ячейка 41 А,е указывает смещение для пе’рвого помещен-
ного слова, а 41С,е—для последнего (в 41С,е всегда
записано смещение непосредственно за словом, содержа-
щим последний введенный символ). Если значения по
адресам 41А,е и 41С,е совпадают, то буфер пуст. Физи-
чески в него может быть помещено максимум 15 двух-
байтных символов. Дополнительные два байта в 32-байт-
ном буфере используются для кодирования клавиши
ВВОД (Enter). В таком случае они содержат коды 13
(D,e) и 28 (1С,е) — скэн-код клавиши ВВОД. Если в не-
которой программе в буфер поместить строку с именем
другой программы, заканчивающуюся парой указанных
34
байтов, то после ее завершения будет запущена на выпол-
нение эта другая программа. При необходимости можно
программно изменять и биты статуса в ячейках 417,6
и 41816- Буфер клавиатуры организован циклически, т. е.
после записи последнего слова со смещением ЗС,е анали-
зируется наличие свободного места в его начале, и если
оно есть, то символы начинают записываться туда. В ре-
зультате может оказаться, что в ячейке 41А,6 записано
большее значение, чем в 41С,6-
Когда буфер заполнен, указатель на его конец на два
меньше указателя на его начало. Исключением является
ситуация, когда указатель на начало буфера равен 30
(lEie). В этом случае буфер заполнен, если указатель
на конец буфера имеет значение 60 (ЗС,е).
Когда скэн-код соответствует клавише, изменяющей
статус (байты 417,6, 418i6), в буфер клавиатуры ничего
не записывается (за исключением состояния клавиши
вставки INS). Программные прерывания ввода с клавиа-
туры BIOS и ОС читают содержимое буфера, подготов-
ленное для них описанной выше служебной процедурой.
Рассмотрим пример программы на языке СИ, работающей с бу-
фером клавиатуры:
finclude <stdio.h>
finciude <dos.h>
void «ain()
{ char ql,q2; int i;
for(i-fl;i<32;i+-2)
/» в цикле впводвтея лесгнадцатервчвпе, jetinuu в ени-
вольвпе звачевня, завноаввие в буфере клавиатуры BIOS в/
{ ql ч peekb(0x40,Oxleei);
q2 - peekbt0x40,Orlfii);
printf("ХЗх) K3x X3d Хс\,\С,Oxle+i,ql,ql,ql);
printf('X3x) I3x 13d Jc\n",0x1f+i,q2,q2,q2); }
1
В ней выводятся все шестнадцатеричные, десятичные и символь-
ные значения, записанные в данный момент.
Вторая программа (тоже на языке СИ) заполняет буфер таким
образом, что после ее завершения запускается первая программа,
которая имеет имя PR4.EXE:
linclnde <dos.h>
void «ainll
{ int i;
char s{] = p\xl9r\il3\x34\x5\id\ilc";
/» s[] - етрова вида: буква p, ее екзн-дод (\х19 = 25);
буква г, ее сдзк-дод (\х13 = 19); цифра 4 (\х34 = 52),
ее сдэк-дод (\хб : 5), управлисций код "возврат каретки"
(\xd = 13), сгзв-год клавиш ВВОД (Enter) (\xlc - 28) »/
роке(0,0х41а,30); /» смеценне начала буфера в области
перемена»! BIOS; адрес начала об-
мин 0x00400; смеценне 30=0х1е »/
35
poke(0,0i41c,3Jt8); /» снедение конца буфера »/
for(1=0;i<8;Itt) /» в буфер BIOS заносится строка
ци вызова программы рг4 после
заверяенна этой програиин »/
pokebfO,Oille+1,s[1]);
На функциональном уровне отдельным клавишам про-
граммным путем ставятся в соответствие определенные
функции, которые реализуются при нажатии этих клавиш.
В зависимости от того, к какой группе отнесена кла-
виша, различаются способы кодирования, принятые
в ПЭВМ. Клавишам первой группы соответствуют простые
ASCII-коды. Однако они могут модифицироваться в за-
висимости от того, нажата ли в это же время клавиша
из четвертой группы либо ранее клавиша из пятой группы.
Клавишам второй и третьей групп соответствуют расши-
ренные ASCII-коды. Если вместе с ними нажать клавишу
четвертой группы, то тоже генерируются расширенные
ASCII-коды, но они будут другими.
Клавишам четвертой и пятой групп не соответствуют
никакие коды. Они лишь влияют на модификацию кодов
предшествующих групп. Дополнительная информация
фиксируется в байтах ОЗУ с адресами 1047 (417i6),
1048 (41816).
При вводе символов с клавиатуры полезно также
знать следующие ее особенности. Одновременное нажа-
тие нескольких клавиш переключателей делает активной
только одну из них (за исключением случая с УПР—
ДОП—УДЛ). Приоритеты распределяются так: 1) Alt
(ДОП); 2) Ctrl (УПР); 3) Shift ( ф )• Любая из клавиш
Shift переводит малую цифровую клавиатуру (справа) в
режим, противоположный режиму, установленному клави-
шей ЦИФ (Num-Lock). Имеется четыре ASCII-кода, кото-
рые формируются двумя способами: 8 — нажатием Back-
Space или Ctrl — Н; 9 — Tab или Ctrl — I;'13 — Enter
или Ctrl — М и 27 — ESC или Ctrl — [. Единственной
клавишей, которая при нажатии меняет статус и заносит
код в буфер, является INS. Она изменяет статус, даже
если буфер полон. Комбинациям клавиши Ctrl с буквами
алфавита соответствуют однобайтные ASCII-коды. В дру-
гих случаях комбинациям с Ctrl соответствуют расши-
ренные коды. Любой ASCII-код, кроме нуля, можно
ввести путем нажатия клавиши Alt, набора десятичного
номера на малой цифровой клавиатуре и отпускания
клавиши Alt. Например, АИ48 даст код нуля. Комбинации
Shift — Prt-Sc, Ctrl — Alt и Sys-Rq для модели АТ (по-
36
следняя в моделях АТ и PS/2 объединена с клавишей
Prt-Sc) приводят к вызову определенной процедуры.
2.2. ВИДЕОДОСТУП
Основным устройством для отображения вводимой
и выводимой информации является дисплей. Поддержка
его работы осуществляется с помощью соответствующего
адаптера (контроллера). В ПЭВМ используются адаптеры
двух типов: одноцветный (монохромный) и цветной графи-
ческий. Изображение на экране формируется в двух основ-
ных режимах — текстовом и графическом. В первом из них
на экран выводятся только символы, во втором можно
строить сложные произвольные изображения. Адаптер
связывает микропроцессор (МП) с дисплеем устройством,
называемым контроллером электронно-лучевой трубки
(экрана). Он имеет программируемые порты ввода-выво-
да, знакогенератор и оперативную (экранную) память,
которая хранит выводимую информацию.
В первых моделях ПЭВМ широко применялся адаптер
типа CGA (Color Graphics Adapter). Как и последующие
устройства аналогичного назначения, он обеспечивал уп-
равление растровыми дисплеями. Образ одного экрана
для CGA хранится в экранной памяти объемом 16 К байт.
Это позволяет отображать 640X200 монохромных точек,
320Х 200 цветных точек и текст (25 строк по 40 или
80 столбцов). Экранная память имеет два порта ввода-
вывода для обеспечения быстрого доступа к ее общему
полю со стороны МП и дисплея. Видеосхема обновляет
экран примерно 60 раз в секунду, делая меняющееся
изображение отчетливым и ясным.
Укрупненная структурная схема адаптера CGA показа-
на на рис. 2.1 [20]. В ее основе лежит микросхема CRTC
(Cathode Ray Tube Controller) 6845 фирмы Motorola,
которая управляет выводом информации на экран. При
работе в графическом режиме каждой точке экрана моно-
хромного дисплея соответствует бит информации в экран-
ной памяти. Если в этом бите содержится единица, то точка
высвечивается, если нуль,— нет. Для того чтобы структура
хранимого образа экрана соответствовала механизму ска-
нирования луча, память дисплея организована в виде двух
блоков. В случае объема 16 К байт они смещены друг
относительно друга на 8 К байт. Первый блок содержит
информацию о точках четных строк, второй — о точках
нечетных строк. В начале первого блока памяти распо-
37
Рис. 2.1. Укрупненная структурная схема адаптера CGA
лагаются биты для нулевой строки на экране. Их 640, что
равно 80 байтам. Следующие 80 байт соответствуют не
первой, а второй строке экрана; затем — четвертой строке,
шестой и т. п. Первой строке экрана соответствуют
80 первых байт второго блока. Адрес первого байта
второго блока отстоит на 8192 от адреса первого байта
первого блока. Во втором блоке хранится информация
для нечетных строк экрана (первой, третьей, пятой и т. п.).
Указанную особенность необходимо учитывать при работе
с экранной памятью.
Цветной режим возможен только при разрешении экра-
на 320 X 200. В этом случае каждой его точке соответст-
вуют два бита в экранной памяти. Четыре возможных
значения в этих битах позволяют задавать один фоновый
и три основных цвета. Последние можно выбирать только
в одной из двух палитр. Палитра 0 включает зеленый,
красный и желто-коричневый цвета, палитра 1— голубой,
фиолетовый и белый (они определяются кодами 01, 10, 11).
Цвет фона может быть любым из 16 (он задается ко-
дом 00). В области переменных BIOS по адресу 0:0466ie
хранится номер текущей палитры (см. табл. 1.3). Доступ
к регистру выбора цвета, который используется только
для записи, осуществляется через порт 3D916- Значения
его бит такие:
1) биты 0—3— фоновый цвет (бит 0—синий, бит 1 —
зеленый, бит 2— красный, бит 3—интенсивность). Всего
38
может быть задано 16 цветов (0000—черный, 0001 —
синий, 0010 — зеленый, 0011 — голубой, 0100 — красный,
0101— фиолетовый, ОНО — коричневый, 0111 — белый,
1000 — серый, 1001—ярко-синий, 1010 — ярко-зеленый,
1011 — ярко-голубой, 1100 — ярко-красный, 1101 — ярко-
фиолетовый, 1110 — желтый, 1111 — ярко-белый);
2) бит 5 — выбор палитры (0— палитра 0,1 — палит-
ра 1).
В текстовом режиме любому отображаемому символу
соответствуют два байта экранной памяти. Байт с четным
адресом специфицирует символ (содержит его ASCII-код).
Данные из этого байта используются для отображения
символа с помощью знакогенератора (см. рис. 2.1). Про-
грамма знакогенератора хранится в ПЗУ дисплейного
адаптера. Байт с нечетным адресом специфицирует режим
отображения (цвет, яркость, мерцание и т. д.). Это
так называемый байт атрибутов. Началом экрана счи-
тается левый верхний угол. Первому символу соот-
ветствуют байты с номерами 0 и 1, второму—2 и 3
и т. п.
В табл. 2.1 указаны коды, которые должны быть за-
несены в соответствующий нечетный байт экранной памя-
ти при задании различных атрибутов отображения. Эта
Таблица 2.1
Код Способ отображения символа
1(1) 7(7) 9(9) 15(F) 112(70) 129(81) 135(87) 137(89) 143(8F) Подчеркнутый линией Нормальный (светлый на темном фоне) Яркий, подчеркнутый линией Яркий (светлый на темном фоне) Реверсивный (темный на светлом фоне) Мигающий, подчеркнутый линией Мигающий нормальный Мигающий яркий, подчеркнутый линией Мигающий яркий
таблица соответствует монохромному режиму отображе-
ния. В ее первом столбце записаны десятичный и в скоб-
ках шестнадцатеричный коды. В случае цветного режима
различные коды в байте атрибута интерпретируются так,
как это показано на рис. 2.2.
В текстовом режиме объем необходимой экранной
памяти составляет 4000 байт для экранов из 25 строк по
80 знаков и 2000 байт для экранов из 25 строк по 40 знаков.
В результате значительные объемы памяти остаются сво-
39
ЦВЕТ ФОНА
1-ЯРКИИ
СИМВОЛ
0
000-ЧЕРНЫИ
001-СИНИИ
010-ЗЕЛЕНЫЙ
011-ГОЛУБОЙ
100-КРАСНЫЙ
101-ФИОЛЕТОВЫй
110-КОРИЧНЕВЫй
111-БЕЛЫй
7 6,5 ,..4 5 2.., 1-тЯ
000-СЕРЫй
001-ЯРКО-СИНИй
010-ЯРКО-ЗЕЛЕНЫЙ
1-МИГАЮЩИЙ
СИМВОЛ
ЦВЕТ
011-ЯРКО-ГОЛУБОй
100-ЯРКО-КРАСНЫй
101-ЯРКО-ФИОЛЕТОВЫЙ
0-НЕТ СИМВОЛА
110-ЖЕЛТЫЙ
JU-ЯРКО-БЕЛЫИ
Рис. 2.2 Назначение битов в байте атрибутов
бодными. Для их эффективного использования в ПЭВМ
применен страничный режим. Страница представляет
собой образ экрана в памяти компьютера. В 80-позицион-
ном текстовом режиме цветной графический адаптер тре-
бует памяти в 4 раза (а в 40-позиционном текстовом
режиме в 8 раз) меньше фактически имеющейся. Поэто-
му память такого адаптера может хранить либо 4, либо
8 страниц. Любая страница представляет собой полную
копию экрана. Информация, хранящаяся в каждой из них,
может быть отображена в любой момент времени. Получив
команду, дисплейный адаптер переключается с одной стра-
ницы на другую, мгновенно обновляя содержимое эк-
рана.
При построении произвольных изображений наряду
с графическим широко применяется псевдографический
режим, когда картинка на экране формируется из специаль-
ных знаков, отображаемых в матрице определенного раз-
мера (для CGA 8X8 точек). Эти знаки кодируются
расширенными ASCII-кодами (диапазон от 128 до 255).
Примерно третья часть этих кодов предназначена для
отображения чертежей и рисунков (остальные — для сим-
волов национальных алфавитов и т. п.). Псевдографи-
ческие элементы представляют собой линии, прямоуголь-
ники, фрагменты штриховки и т. п. Изображение из них
собирается так же, как из мозаики. Один из векторов
прерывания (прерывание с номером 31) используется для
указания на расширенную таблицу ASCII. В результате
ее можно менять и подстраивать под собственные нужды.
Преимущество псевдографического режима заключается
в том, что используется меньший (примерно в 4 раза)
объем экранной памяти. Для фрагмента экрана 8X8 то-
чек в графическом режиме требуется 8 байт, а в псевдо-
графическом — только 2 (байт символа и байт атрибутов).
40
Более подробные сведения об адаптере CGA приведены
в работе [3].
С конца 1984 г. основным контроллером для органи-
зации видеодоступа на ПЭВМ стал улучшенный графи-
ческий адаптер EGA (Enhanced Graphics Adapter), кото-
рый может быть оснащен экранной памятью объемом 64,
128 или 256 К байт. На ПЭВМ семейства PS/2 установлено
еще более новое устройство VGA (Video Graphics Adap-
ter) . Для расширения возможностей этих адаптеров введе-
ны новые программные средства низкого уровня в ПЗУ
(объем 16 К байт), которые дополняют процедуры BIOS
работы с терминалом. Начало области ПЗУ находится
по адресу С000 • 0000.
В ПЭВМ применяются дисплеи трех типов: компо-
зиционные, цифровые и аналоговые. Композиционный мо-
нитор получает аналоговый сигнал, подобный тому, кото-
рый используется в телевидении. Для его передачи до-
статочно одной линии. У оригинального цифрового цвет-
ного RGB монитора фирмы IBM три входа для цвета
(красный, зеленый, синий) и один для интенсивности.
Улучшенный цветной дисплей имеет 6 входов: RGBrgb.
Первые три (RGB) дают 2/3 интенсивности красного,
зеленого и синего лучей, вторые три (rgb) — 1/3 интен-
сивности. Одновременное возбуждение двух одноименных
входов (например, R и г) дает единицу интенсивности.
В этом случае уже можно получить 26= 64 цвета. Даль-
нейший рост числа цветов связан с увеличением числа
входов. Аналоговый монитор имеет три входа для RGB
сигналов. Интенсивность луча в нем регулируется уровнем
напряжения на соответствующей линии, вследствие чего
здесь имеется возможность получения практически неогра-
ниченного числа цветов с плавными переходами между
ними. Адаптер CGA поддерживает композиционный или
RGB монитор, адаптер EGA — RGB или RGBrgb, VGA —
аналоговый монитор.
Регистровая организация адаптеров EGA/VGA пока-
зана на рис. 2.3 [20]. Адаптер EGA позволяет выбирать
цветовую палитру, включающую до 16 цветов из 64 воз-
можных. Различные цвета образуются комбинациями рас-
смотренных выше сигналов RGBrgb. Режимы отображе-
ния информации для всех адаптеров (CGA, EGA, VGA)
сведены в табл. 2.2 [20]. Заметим, что в графическом
режиме, как и в текстовом, может быть организовано
несколько страниц, каждая из которых представляет
в дисплейной памяти полную копию экрана.
41
Рис. 2.3. Регистровая организация адаптеров EGA/VGA
Таблица 2.2
Режим Адаптер Тип Номер страницы в дис- плейной памяти Количество Сегмент
символов точ ек цв етов
1 2 3 4 5 6 7 8
40X25 320X200 16
0,1 CGA
1
2
3
4
5
6
7
8
В800
В880
В900
В980
BA00
В А 80
BB00
ВВ80
42
П родолжение табл. 2.2
1 2 3 4 5 6 7 8
0,1 EGA T 1 40X25 320X200 16/64 В800
2 В880
3 В900
4 В980
5 BA00
6 ВА80
7 ВВОО
8 ВВ80
0,1 VGA T 1 40X25 360X400 16/256К В800
2 В880
3 В900
4 В980
5 ВАОО
6 В А 80
7 ВВОО
8 ВВ80
2,3 CGA T 1 80X25 640X200 16 В800
2 В900
3 ВАОО
4 ВВОО
2,3 EGA T 1 80X25 640X350 16/64 В800
2 В900
3 ВАОО
4 ВВОО
5 ВСОО
6 BD00
7 ВЕОО
8 BFOO
2,3 VGA T 1 80X25 720X400 16/256 К В800
2 В900
3 ВАОО
4 ВВОО
5 ВСОО
6 BD00
7 ВЕОО
8 ВЕОО
4,5 CGA г 1 40X25 320X200 4 В 800
EGA г 1 40X25 320X200 4/64 В800
VGA г 1 40X25 320X200 4/256 К В 800
6 CGA г 1 80X25 640X200 2 В 800
6 EGA г 1 80X25 640X200 2/64 В800
6 VGA г 1 80X25 640X200 2/256 К В800
7 MA т 1 80X25 720X350 4 ВООО
7 EGA т 1 80X25 720X350 4 ВООО
2 В100
3 В200
4 ВЗОО
5 В400
6 В500
43
Окончание табл. 2.2
1 2 3 4 5 6 7 8
7 В600
8 В700
7 VGA T 1 80X25 720X400 4 вооо
2 вюо
3 В 200
4 взоо
5 В400
6 В500
7 В600
8 В 700
D EGA г I 80X25 320X200 16/64 А ООО
2 А 200
3 А400
4 А600
5 А 800
6 AA00
7 АСОО
8 АЕОО
D VGA г 1 80X25 320X200 16/256 К А ООО
2 А 200
3 А400
4 А600
5 А 800
6 ААОО
7 АСОО
8 АЕОО
Е EGA г 1 80X25 640X200 16/64 А000
2 А400
3 А800
4 АСОО
Е VGA г 1 80X25 640X200 16/256 К А000
2 А 400
3 А 800
4 АСОО
F EGA г 1 80X25 640X350 4. А ООО
2 А800
F VGA г I 80X25 640X200 4 А000
2 А 800
10 EGA г 1 - 80X25 640X350 16/64 А000
2 А 800
10 VGA г 1 80X25 640X350 16/256 К А000
2 А 800
11 VGA г 1 80X30 640X480 2/256 К А ООО
12 VGA г 1 80X30 640X480 16/256 К А ООО
13 VGA г 1 40X25 320X200 256/256 К А000
Примечания: 1. Г — графический режим; Т — текстовой.
44
2. Числа в графах 1 и 8 — шестнадцатеричные, в остальных гра-
фах — десятичные.
3. Выражение вида 16/256 К означает, что можно выбирать любые
16 цветов из 256 К возможных (К=Ю24).
Один конкретный цвет задается содержимым одного
восьмиразрядного регистра палитры (всего их 16). Для
адаптера EGA в разрядах 6—7 всегда содержатся нули,
а биты 5—0 соответствуют линиям rgbRGB (наличие
единицы в бите говорит о том, что будет выработан
сигнал соответствующей интенсивности). Регистры палит-
ры находятся в составе регистров атрибутов. Для выбора
цвета точки надо указать для нее конкретный регистр
с помощью четырехразрядного двоичного кода. Значение
в нулевом регистре палитры используется в качестве
фонового цвета. Программа может изменять все выводи-
мое в одном цвете на другой цвет без обращения к
экранной памяти. Если некоторый объект вычерчен цве-
том п, то после записи значения п в регистр фона с номе-
ром 0 этот объект исчезнет с экрана (хотя на самом деле он
хранится в памяти). Он снова станет видимым после заме-
ны фонового цвета.
Каждому разряду указанного выше четырехразряд-
ного кода соответствует область экранной памяти, назы-
ваемая битовой картой или битовым планом (bit plane).
Всего может быть до четырех таких планов (см. рис. 2.3).
Одноименный байт в каждом из них может адресоваться
одновременно. В связи с этим все они могут иметь один
и тот же сегментный адрес (см. табл. 2.2). Тогда седьмые
(последние) биты в четырех нулевых байтах задают цвет
нулевой точки на экране, шестые биты — первой точки и
т. п. (старший бит с номером 7 в каждом байте
соответствует самой левой точке для этого байта). Преиму-
щество такой организации состоит в том, что местополо-
жение бита в любом плане соответствует точке, для кото-
рой он предназначен на экране дисплея. В двухцветном
и четырехцветном режимах берутся соответственно первые
два и четыре регистра палитры, но они могут содержать
любые из 64 цветов. Адаптер VGA в отличие от EGA при
разрешении 320X 200 точек позволяет использовать 256
цветов. В этом случае при кодировании на каждую точку
экрана отводится один байт. Такие байты размещаются
в памяти непрерывно друг за другом. Подробнее об этом
можно прочитать в книге [16, с. 82].
Механизмы работы с адаптером EGA/VGA на самом
45
деле намного сложнее. Для управления этими адаптера-
ми и режимами отображения введены специальные блоки,
содержащие большое число регистров, к которым програм-
мист имеет доступ через порты.
В дальнейшем наше изложение будет построено таким образом:
сначала дается обзор всех портов и регистров по группам, затем
подробно характеризуются наиболее важные регистры, показаны при-
емы работы с ними и приведены программы на языках СИ и ассемб-
лера. Отдельные программы довольно сложны, и перед их рассмотре-
нием имеет смысл ознакомиться с гл. 6, 8, 12.
Управляющие регистры EGA/VGA (см. рис. 2.3) де-
лятся на 6 групп (последняя группа — только для VGA):
1) внешние регистры (external registers);
2 регистры секвенсора (sequencer registers);
3) регистры CRTC (Cathod Ray Tube Controller), ко-
торые управляют режимами синхронизации и вывода
информации на экран;
4) регистры графического контроллера (graphics con-
troller registers);
5) регистры атрибутов (attribute registers);
6) регистры цифроаналогового преобразования (Di-
gital to Analog Converter—DAC).
Охарактеризуем кратко регистры каждой группы.
1. Внешние регистры включают: выходной регистр,
выполняющий разнообразные функции (изменение часто-
ты синхросигналов, параметров развертки дисплея и
т. п.),— порт ЗС2|6; регистр входного статуса для диагно-
стики и синхронизации — порт 3BAie для монохромного
и 3DA16 для цветного дисплея; регистр разрешения
видеоподсистемы— порт 3C316 (для VGA).
2. Регистры секвенсора работают только на запись и
включают 5 наименований. Номер каждого из них (от
О до 4) может быть выбран с помощью индексного
регистра — порт ЗС4,6. Данные записываются через порт
ЗС516- Каждый индекс задает: 0—регистр сброса; 1 —
регистр режима синхронизации; 2 — регистр маски пла-
нов; 3 — регистр выбора блока для символов; 4 — регистр
режима работы (бит 0:0 — графика, 1 — текст; бит 1:0 —
нет расширения памяти, 1 — есть; бит 2:0 — работа с чет-
ными и нечетными страницами дисплея, 1 — работа с по-
следовательно идущими страницами; бит 3:1 — 256 цветов
только для VGA; биты 4—7 не используются).
3. Регистры CRTC включают 25 наименований. Ин-
дексный регистр находится в порту ЗВ416 для монохром-
ного и 3D416 для цветного дисплея. Передача данных
46
осуществляется соответственно через порты ЗВ5|6 и 3D516.
Некоторые из регистров будут рассмотрены ниже.
4. Регистрам графического контроллера соответствую!
порты ЗСС16 (графика 1) и ЗСА16 (графика 2), которые
используются только для EGA. Адаптеры EGA/VGA име-
ют дополнительно 9 регистров данных (порт 3CF[6) и ин-
дексный регистр (портЗСЕ1б). Сначала необходимо пере-
дать индекс в порт ЗСЕ,6 и затем получать и передавать
данные через порт 3CF16. Заметим, что номера портов для
различных групп следуют непосредственно друг за другом,
поэтому для их адресации в языке ассемблера можно
использовать операции inc и dec. Сначала мы этого делать
не будем с целью явного указания соответствующих
объектов (возможно, это лучше для понимания). Каждый
индекс задает: 0 — регистр установки/сброса графиче-
ских данных; 1 — регистр разрешения установки/сброса
для индекса 0; 2 — регистр сравнения цвета; 3 — регистр
вращения (перемещения) данных; 4 — регистр выбора
плана для чтения; 5 — регистр выбора режима; 6 — мно-
гофункциональный регистр (бит 0: 0 — текстовой режим,
1 — графический режим; бит 1 задает изменение четного
плана на нечетный; биты 2—3 задают экранную память:
00— сегмент А000— 128 К байт; 01 — сегмент А000 —
64 К байта; 10 — сегмент В000 — 32 К байта; 11 — сег-
мент В800 — 32 К байта); 7 — регистр безразличия цве-
та; 8 — регистр битовой маски.
5. Регистры атрибутов включают 21 наименование.
Для работы с конкретным регистром необходимо сначала
переслать в любую переменную значение из порта
ЗВА16 для монохромного и 3DAi6 для цветного дисплея,
далее послать в регистр адреса ЗС0|б требуемый индекс
и, наконец, передать данные через этот же порт. Наиболее
обширную группу с индексами 016—Fie (0—15) составляют
16 регистров палитры. Они уже рассматривались выше.
Далее идут: 16 — регистр управления режимами; 17 — ре-
гистр цвета окаймления экрана; 18 — регистр разрешения
планов; 19 — регистр горизонтального перемещения, по-
зволяющий сдвигать изображение влево на заданное число
точек; 20 (только VGA) — регистр выбора цвета.
6. Блок DAC (только VGA) включает 256 регистров,
каждый из которых определяет один цвет и имеет размер
18 бит (по 6 бит для красного, зеленого и синего
цветов). Таким образом, общее число потенциально во-
зможных цветов равно 262 144 (т. е. 256 К). Блок DAC
имеет следующие порты: 3C6ie — регистр маски (он ини-
47
циализируется средствами BIOS и не должен изменяться
прикладными программами): ЗС716 — регистр выбора ин-
декса для чтения (необходимо ждать, когда в его битах
О—1 будут нули, и далее устанавливать адрес от 0 до 255
для чтения); ЗС816 — регистр выбора индекса для записи
(необходимо ждать, когда в битах 0—1 порта ЗС716 будут
единицы, и далее устанавливать адрес от 0 до 255 для запи-
си); ЗС916 — для передачи и приема данных в регистры
(биты 0—5) по адресам, установленным в 3C7i6 или ЗС8,6-
При записи и чтении данных передаются три байта, в кото-
рых используются 6 бит. Сначала пересылается интенсив-
ность красного цвета, затем зеленого и, наконец, синего.
Все начальные значения этих регистров приведены в кни-
ге [20]. Дополнительную информацию по этому вопросу
можно получить в работе [16].
Рассмотрим приемы работы с определенными группами регистров.
Как отмечено выше, в расширенных графических режимах адаптеры
EGA/VGA используют память не так, как адаптер CGA. Однако в
общих режимах они функционируют одинаково. При работе в графиче-
ском режиме могут выводиться и символы, при этом их изображение,
составленное из точек, копируется в экранную память. В качестве
первого примера покажем работу с регистрами палитры. Чтобы обра-
титься к регистру п, необходимо сначала прочитать значение из порта
ЗВАц для монохромного дисплея и из порта 3DA,o для цветного (на-
пример, mov dx, 3DAH и in al, dx). Далее надо послать номер регистра
п в порт ЗСО, а, затем передать в порт ЗСО,в измененный цвет и, наконец,
разрешить вывод изображения на экран установкой бита 5 порта ЗС0,е
в единицу.
Ниже приведен пример программы на языке СИ, позволяющей
выполнять изменение цвета color (от 0 до 63) в одном из регистров палит-
ры п (от 0 до 15):
•include <3tdio.h>
•include (graphics h>
•include cdos.h) B,
void uain()
( unsigned int color,
int gd=DETECT,gi;
put3('honep регистра палитры (от 0 до 15)?‘);
scanfCXd',4п); /* ввод номера регистра палитры »/
putsf"Иовый цвет (от 0 до 63)?');
scanf('Xd',4color), /» ввод номера цвета »/
initgraph(4gd,4ga,"'), /• инициализация графики «/
/t 1) прочитать значение нз порта 3da (иди ЗЬа ди моно);*/
/т 2) поедать индекс регистра в порт ЗсО (бит 5 - 0); >/
/« 3) поедать иомер цвета дли выбранного регистра в ЗсО; «/
/т Ц разренить вывод ца экран установкой бита S в 1. •/
/tTtttttttttttttttuintttttttmutttmttuttTtuumtt/
inportb(Ox3da); /« обравение к порту 3da для инициали-
зации адресного регистра (порт ЗсО) т/
48
outportbfОхЗсО.пI, /* запись индекса в порт ЗсО,
при этом бит 5 в нуле и за-
дается установка регистра */
outportbf0x3сО,color);/* запись цвета в регистр п */
inportb!0i3da); /* инициализация адресного регистра «/
outportbf0x3сО,0x20); /» установка бита 5 в единицу ди
разренеиия вывода информации иа экран дисплея */
/* при о=0 н colocxi, эта окрулность не будет видна «/
setcolor(l); /* установка синего цвета »/
circle!200,200,100); /* рисование окрулности (8=100) */
/* прн о=0 н eolor=2, зга окруаность не будет видна */
setcolor(2); /* установка зеленого цвета */
cite 1е(200,200,50); /» рисование окрулности (8=50) »/
geteh(); /* налать любую клавииу */
closegraph!); /* заверненне работы с графикой */
)
Рассмотрим некоторые приемы работы с экранной памятью. Пока-
жем, как путем прямого доступа к видеобуферу отобразить точки раз-
личного цвета. Для этого необходимо вычислить смещение точки в
экранной памяти (т. е. найти байт и бит внутри этого байта) и изменить
биты во всех планах для получения нужного цвета. У адаптеров
EGA/VQA режимы О—7 (см. табл. 2.2) аналогичны режимам адаптера
CGA, a D|6—Юге совершенно другие. Для случаев Dm, Еде и Юге экран-
ная память разбита на четыре плана. Рассмотрим, как осуществляется
запись в них данных, поступающих от МП. В адаптере используются
четыре специальных буферных регистра (latch register). Они содержат
данные для четырех планов и связаны с байтами, адреса которых
указывались при последнем обращении. Когда МП посылает данные, то
может быть изменено содержимое буферных регистров, значения которых
впоследствии переписываются в планы. При чтении из экранной памяти
по указанному адресу буферные регистры заполняются из четырех
байтов четырех планов по этому адресу.
Способ взаимодействия МП с буферными регистрами определяется
используемым режимом и содержимым некоторых других регистров. Для
защиты определенных битов или планов от влияния данных МП исполь-
зуются регистр битовой маски (порт 3CFie, индекс 8) и регистр маски
планов (порт ЗС5;6, индекс 2). Оба они работают только на запись. Если
в первом регистре установить i-й бит (i= 0...........7) в нуль, то он маски-
руется во всех четырех планах. Обратим внимание на то, что перед
записью по выбранному адресу необходимо считывать из него (для на-
стройки на адрес четырех буферных регистров). Биты 0—3 второго
регистра соответствуют планам 0—3 (биты 4—7 не используются).
Когда j-й бит (из первых четырех) равен нулю, то j-й план не изменяет-
ся при операциях записи.
Режимы 0—2 устанавливаются регистром выбора режима (порт
3CF|6, индекс 5). Первый из них (00 — в битах 0—1) пересылает данные
МП в каждый из четырех планов с учетом значений в указанных
выше двух регистрах маски. Регистр маски плана запрещает измене-
ние планов, но не обнуляет их. Поэтому необходимо предварительно
очищать все битовые плоскости перед заданием нужных цветов. Это
делается установкой нуля по заданному адресу при условии, что можно
записывать во все планы. Режим 0 работает иначе, если разрешена
установка/сброс (порт ЗСЕщ, индексы О, 1). BIOS инициализирует этот
режим в неактивное состояние. Регистр с индексом 1 разрешает уста-
новку/сброс для регистра с индексом 0. Биты 0—3 обоих регистров
соответствуют планам 0—3, а биты 4—7 не используются.
49
Режим 1 полезен для быстрого переноса данных из одной части
экрана в другую. В этом режиме текущее содержимое буферных
регистров, которые заполняются операцией чтения, переписывается в
указанное место планов. Регистры маски битов и планов не влияют на
режим 1.
Режим 2 реализует другой способ отображения точек. В данных,
поступающих от МП, биты 0—3 воспринимаются как двоичный код
номера регистра палитры (биты 4—7 не применяются). Соответствующие
значения записываются для выбранной точки во все четыре плана. Ре-
гистры маски используются так же, как в режиме 0.
Ниже приведен пример работы для всех трех режимов (0—2) на
языках СИ и ассемблера:
iincliide (stdio.h)
finclude <dos.b>
extern int ayas»3(int,int,int,int,int,int,int);
/» int, int, int,-int, int, int, int -- номер рехнма,
номер 6am с точкой, маска ди байта, цвет точки,
признак внпохнення рехмма 1, сегментам! адрес видео-
буфера, номер рехнма ди функции 0 прернвання 0x10 */
void »aln()
[ unsigned int a,b,c,d,pr,v.nbios;
putsfJOMep рехнна (0 ни 2)?');
scant CM",4a);
pntsfBoMep байта с точкой (0 - FFFF)?");
scanf("Jx',4b);
putsfKacxa ддя байта (0 - FF)?");
scanf("tx",4c):
рйвСЦвет точхн (0 - F)?’);
scanf(’Jx',4d);
pntsfEcxa внпохнять дополнительно рехнм 1, введмте Г
Лпнначе - О’);
scant fid’ ,4pr);
1нЛн(’Сегментннй адрес видеобуфера {от 4000)?’);
scant("Ди",4v);
patsfloMep рехнна ддя прерывания BIOS (D,Е,F, 10)?’);
scant fix’, inbios);
ayasa3(a,b,c,d,pr,v.nbios);
getchf); /в ди прододхеная махайте лабуа хданнау </
/в восстамовденае нервоначальмого рехнма (он бах мзмемен
в нрограмме вуазвЗ на язике ассемблера) в/
ЛН = 0; JL а 3; geninternipt(OxlO);
J »'
.MODEL SHALL ; объявление малой модели
; Область данным ддя значений переменных, ;
; подученным нз программу на языке СМ ;
.DMA
aode DM ? ; неренеиная а
kbyte DM ? ; неременная b
tap DM 9 ; нерешенная с
color DM 9 ; переменная d
cop DM 0 ; переменная РГ
v DM ? ; перенеыкая V
nbios DM 9 ; нерешенная nbios
.CODE ; сегмент кода
PUBLIC дауазаЗ ; вуазаЗ, доступная из другого язнка
50
луазвЗ РВОС ; начало программы
;tlUHttmiHU>ttU>BIUUUIItlUI>U;
; Чтение значение аргументов, переданных ;
; нз нрограимн на языке СИ ;
push bp ; значение bp помечается в стен
bov bp,sp
вот bx, [ЬрН] ; в bx передается значение а
bov node,bx
bov bx,[bp+6] ; в bx передается значение b
bov bbyte,bx
bov bx,[bp»8] ; в bx передается значение с
bov nap.bx
bov bx,[bp+10J ; в bx передается значение d
’ bov co lor,bx
bov bx,[bptl2] ; в bx передается значение рг
bov cop,bx
bov bx, [bpt-14] ; в bx передается значение v
bov v,bx
•ov bx,[bp+16] ; в bx передается значение nbios
bov nbios,bx
pop bp ; значение bp читается нз стена
; Установка рехнха nbios работы дисплея (значение ;
nbios передается нз программы на языке СИ)
bov ах,nbios ; возмохные значения nbios: B,E,F,1O
bov ah,0 ; функция И прернвания ЮН - выбор рехнма
int 10В ; внзов прернвання 10В
; Установка рехнха записи для адаптера EGA, здесь: ЗСЕ
; нндексннй регистр графического контроллера; 3CF -- ;
; порт регистров данник; 5 -- регистр внбора рехнха ;
bov di,3CEH ; внбор пятого регистра графического
bov al,5 ; контроллера EGA (нз группн
out dx,al ; Graphics Controller Register)
bov dx,3CFB ; выбор порта регистров данных
bov ах,node ; рехнх node задается в программе на СИ
out dx.al ; рехнх (от 0 до 3) нереснлается в порт
; В es:bx заносится адрес видеобуфера (es - сегхентннй ;
; адрес v, bx - схеценне bbyte). Значения v и bbyte не- ;
; редавтся нз программа на язнке СИ
bov ax,v ; нанхеныее значение v MOO
bov es,ax
bov bx,bbyte ; значение bbyte в диапазоне 0 -- FFFF
; Маскирование всех битов, крохе тех, которне заданн ;
; еднннцаин в значеннн вар (это значехне передается нз ;
; програххн ха СИ (8 -- похер регистра битовой хаскх) ;
bov dx,3CEH ; хндексннй регистр граф, контроллера
bov al,8 ; регистр битовой хаскн
out dx.al ; выбор регистра битовой хаскн
bov dx,3CF0 ; внбор порта регистров даппнх
вот ах,вар ; запись заданной битовой хаскв в
out dx,al ; внбранный регистр
51
; Чтение н обнуление содерхнмого буферного регистра ;
;тшттиш?штттитиишштти;
ov al,es:[bx] ; чтение содерхнмого буферного регистра
mv al, О
ov es:[hx],al ; обнуление буферного регистра
»»»»»»»»»»»»»(»»»»»»»»»!»»»;
; Установка регистра маски ди цвета color, значение ;
; которого получено нз програиин на СМ, здесь: ЗС4Н - ;
; индексный регистр секвеисора; 2 - регистр маски •,
ov dx,3C40 ; в индексный регистр записывается
вот al,2 ; номер 2-го регистра маскн
out dx.al
ov dx,3C5B ; 3C50 - порт, в которнй пниутся данные
ov ах,color ; запись цвета color в регистр маскн
out dx.al
;»»»»»»»»»»»»(«»»»»»»»»»»»»»»»;
; Внчерчнванне задании! точек ;
; тишштпттшш;
ov al,OF20 ; здесь мохет бить лвбое значение
; с установлениями бнтамн кар
ov es:[Ьх],а1 ; внвод точки
;пшшцииит1ттттищтишштит;
; Демонстрация рехнма 1 (если переменная сор, получен- ;
; ная нз програнмн на языке СИ, не равна нуд» ;
cap сор,0 ; если сор = 0, то переход
je quit ; г метке quit
ov dx,ЗСЕН ; следуидне месть строг аналогиями
ov al,5 ; нрерндуцнм, но выбирается рехнм 1
out dx.al
ov dx,3CFB
ov ax,l ; внбор рехнма 1
out dx.al
»»»»»»»»»»»»»»»;
; Коннрованне строки в следувдув строку ;
;»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
ov сх,80 ; задается число байтов в строке
ov bx.bbyte ; отсчет от байта bbyte (нз СИ) буфера
ov ax,v ; v - сегментний адрес буфера (нз СИ)
ov ев,ах ; сегментний адрес заносится в ев
Ip: iov al,ев:[Ьх] ; в зтом цикле байтн одной строки
ov ев:[bx]t80,al ; перепнснвавтся в другу» (сдедув-
inc bx ; му») строку •:
loop 1р
quit: ret
_>yasa3 ENDP
KHD
; возврат мз ассемблерной нрограмин
; гонец програиин
В программе на языке СИ вводятся все необходимые данные для
отображения в выбранной области экрана от 0 до 8 точек заданного
цвета. Полученные данные записываются в программе на языке
ассемблера в указанную область видеобуфера. Эксперименты с програм-
мами позволяют детально изучить все режимы.
В адаптерах EGA/VGA имеется возможность модификаций содер-
жимого буферных регистров (режим записи 0). С этой целью произ-
водится обращение к регистру вращения (перемещения) данных (порт
52
3CFie, индекс 3). Его биты 2—0 показывают, на сколько позиций вправо
необходимо сдвинуть содержимое буферных регистров. Здесь выполняет-
ся циклический сдвиг (из самого правого бита в самый левый), что
оправдывает термин «вращение». Биты 4—3 задают операции над дан-
ными (00—нет модификации, 01 — операция Логическое И с буферным
регистром, 10 — операция Логическое ИЛИ с буферным регистром,
11 — операция Исключающее ИЛИ с буферным регистром), Биты 5—7 не
используются.
Ниже приведен пример работы с регистром вращения. Программа
написана на языках СИ и ассемблера; она позволяет задавать наклон
вправо и влево для символов, выводимых на экран в графическом
режиме:
^include <stdio.b>
extern int iyasi4(int,int,int,int,int,int,int,int,int,int);
void tnainf)
[ unsigned int str,col,node,s,Ipl,lp2,lp3,roti,
rot2,rot3,r,rot;
pntsfCTposa, начиная с которой отобрахаися снмводн?");
' scant("Xd",4str);
putsfltoioHKa, с которой начнется отобрахенне’");
scant("Xd",icol);
putsfdoMep рехама (0 - 4)?');
scanffXd",diode);
pntsfdasioH (0 - нет, 1 - вправо, 2 - вхево)?");
scant("%d",&rot);
puts('3axaTB рехнм по умодчанн! - l;\n"
"задать рехнм подьзоватедем - 0 (?)");
scant("Xd*,4r);
if (r) if (lode " 3) [ Ipl = 5; lp2 4; lp3 5; 1
else [ Ipl : 3; lp2 "- 2; 1рЗ : 3; 1
else [ puts("Введите чнсдо днннй\пв верхней, '
"средней н ннхаей части сннвода!");
if (lode " 3) putsf( суммарное чнсдо 14");
else puts("(суммарное чнсдо 8");
scanf("XdXdXd",41pl,41p2,41p3); 1
if (r) snitch (rot) [
case 0: rotkOxlO; rot2=ixl0; rot3=0xl0; break;
case L rothOxll; rot2:OxlO; rot3:0xl7; break;
case 2: rot 1=0x17; rot2=0xl0; rot3=0xll; break;
default: puts("oiH6o4Hoe задание наддона");]
else [ puts("Задайте перемеценне\пдхя верхней, "
"средней н ннхней части С1мвода\п"
"(значения шестнадцатернчнне)?");
scant("ХхХхХх",drotl,drot2,4rot3); ]
s : Ipl t lp2 t lp3;
iyasi4(str,col,node,s,Ipl,lp2,lp3,roti,rot2,rot3);
1
.MODEL SHALL ; объявденяе надой модедн
; Обхасть данных ддя значений переменннх, ;
подученных нз программн на язнке СИ ;
.DATA
str DH 3 ; строка, с которой качнется отобрахенпе
col DH 1 ; кодонка, с которой начнется отобрахепн
ode DH 1 ; номер рехама
53
s BK 1 ; число горизонтальна! цини в символе
; оинсанне горнзонтальних линий символа. Значения 3,2,3
; заданы на уиомчаннв ддя символа размером 8x8
Ipl DK 3 ; чнсю днннй ддя верхней часта символа
1р2 DK 2 ; чнсю ланнй ддя средней части снмвода
1рЗ DK 3 ; чнсю инне ддя ннхней части снмвода
; значение регистра неремеденяя (нндехс 3, порт 3CF) соот
; ветствепно ддя Ipl, 1р2 и 1рЗ днннй в символе
roll DK 118 ; регистр неремедення ддя верха символа
то12 ОН ЮН ; регистр неремедення для середнын свмво
го13 DK 17В ; регистр неремедення ди низа символа
; sto а п_с внутренние неремемнне (нз СВ не передаются)
sto DK ? ; нромедрточная вмутреныяя неременная
п_с DK 80 ; чнсю юдонок в одной строке
.STACK 208
.СОНК ; сегмент кода
include dos.inc ; подключение макросредств ассемблера
PUBLIC jyasal ; ayasal, достунмая нз другого язнка
jyasM РВОС ; начало програнмн
•, Чтение значений переданная аргументов ;
; нз программы на язике СИ ;
push bp ; значение bp нонедается в стек
aov bp,sp
aov bx,[bpH] ; в bi передается значение str
доч str.bx
aov bx,{bp»6] ; в bx передается значение col
aov col.bx
aov bx,[Ьрг8] ; в bx передается змаченяе aode
aov aode.bx
aov bx,[bptlO] ; в bx передается значение s
aov s,bx
aov bx,[bptll] ; в bx передается значение Ipl
aov Ipl.bx
aov bx,[bptll] ; в bx передается значение 1р2
aov lp2,bx
aov bx,[bptl6] ; в bx передается значение 1рЗ
aov lp3,bx
aov bx,[bptl8] ; в bx передается значение roti
aov rotl.bx
aov bx,[bpt20] ; в bx передается значение rot.2
aov rot2,bx
aov bx,[bpt22] ; в bx передается значение rot3
aov rot3,bx c
pop bp ; восстанавливается значение bp
; Установи ds на область DATA и сохранение значения ;
col в nepenennoi sto ;
;тшпт**1п*тш***»тпш*****птш*ч»;
aov ax.SDiiTA
aov ds,ax
aov bx,col
aov sto.bx
; Установка реянма 108 для адаптера EGA ;
aov ax,108 ; функция 0 (АН = 0)
int 108 ; прерывание 218
54
; Рехнм отобрахення снмвоков дхя EGA ;
ov ax.mode ; mode - номер табхмцн jn генератора
ют ЬЬ,а1 ; знаков (пересылается в ЬЬ)
bov ах,11308 ; подфункция ЗОН функции 118
int 108 внзов врернвання 108
; Ввод символа с елавматурн ;
agn: »ov ah, 6 ; функция 6 нрернвапия 218
bov dl.OffB ; значение f18 устапавивает рехнм ввода
int 218 ; символа с елавнатурн
jz agn ; новтор до ввода сямвода
; Проверка выхода во ESC ;
; ШВ I U 1ШШ1 ***** ВШ;
bov ab,0
свр al,27 ; 27 - ASCll-код кхавнвн ESC
je quit ; если наката клавниа ESC, внмод
bov Ьх,s ; в bi - число горнзонтальннх шнй символа
ви1 Ы ; уинохается ASCll-код символа (в ах) на
; чнсю линий, вз которых он состоит (для
; внбора нухной лнннн в табмнце генератора
; знаков). Результат помечается в ах
add ах,bp ; bp - снеценне таблнцн генератора знаков,
; возвращаемое подфункцией 308 функции 118
', прернвання 108 (см. ранее в программе)
call scr_siB ; внзов процедуры scr.six
;****************************************;
; Смеаенне ди вывода следувцего символа ;
;****************************************;
add col, 1 : ; нонер колонки увеличивается на единицу
cup col,80 ; ; нроверяетсн достнхенне конца строки
jb qo ; ; нет перехода на новув строку
mov hx.sto ; ; переход на новую строку: в col запи-
aov col,bx ; ; снвается нонер начальной кохонкн (за-
add str,l ; ; дан в СИ), внбнрается новая строка
cap str,25 : ; проверяется достнхенне конца экрана
jb no ; нет достнхення конца экрана
jup quit ; ; достнхенне конца экрана - внход
no; jap agn ; переход к вводу очередного сиивока
;******************»**************»*****************;
; Вереход к исходному рехнм; н завервенке програш ;
quit: вот ах,3 ; устанавливается рехнм 3 (80x25)
bov ah,0 ; для вядеодоступа (функция 0 пре-
int 10Ь ; рываяяв 108)
SExit ; макросредство выхода нз программн
jyasii endp ; конец процедуры endp
;******************************;
; Вызываемая процедура scr^sin ;
scr.si» proc веаг
; Определение координат вычерчивания символа ;
iov сх।fl ; очястка регистра ex
bov si,ax ; в si - сме<ея1е енмвода
55
iov ii,n_c ; в di сохраняется чнсю кохонох
iov ах,str ; в ах заносится номер текудей строки
ноя bx,s ; в Ъх заносится чнсхо ханнй и снмвохе
«и! Ъ1 ; умиохаем на час» точек в строке
mil di ; уинохаем на чнсхо колонок
add ах,col ; окоичатехьио суммируем с текуцей
; кохонкой чтобы вспучить смеиение
iov Ъх.ах ; сохранней сиеценне в Ъх
push ds ; сохраняем ds в стеке
;штхш ***********************шиитмшш**;
; Сохракенне значения Ipl, 1р2, 1рЗ, roti, rot2, rot3 н ;
; стеке (непосредственно нт мспохьзовать нехьзя.так как ;
; внхе ds будет содерхать сегмент вндеобуфера, a es ;
; сегмент табхяцн дхя генератора знаков) ;
;*******************************************************;
aov dx,1рЗ
push dx ', сохранение 1рЗ
вот dx,rot3
push dx ; сохранение rot3
вот dx,1р2
push dx ; сохранение lp2
bov dx,rot2
push dx 1 сохранение rot2
bov dx.lpl
push dx ; сохранение Ipl
bov dx.rotl
push dx ; сохранение roti
;**********************************************;
; Установка регистра ds на сегмент видеобуфера ;
;*****»*****»*********»***********«************;
bov ах.ОаОООВ : сегмент намята дхя рехнма 10В
bov ds,ах ; в ds сегмент видеобуфера
;**********************************;
; Установка регистра битовой маски ;
злшшщтщштшшпш;
bov dx,3ceB ; индексный регистр граф, контропера
bov al,8 ; 8 - регистр битовой маски
out dx.al ; установка регистра битовой маски
bov dx,3cfS ; 3cfB - порт ддя регистра данных
bov al.OfeB ; запрет завися в нухевой бит
out dx.al ; значение al в регистр битовой маски
^uumuumutuutumunuuut
; Установка регистра изменения данных ;
;*************************************;
bov dx,3ceH ; индексный регистр граф. контроххерас
bov al,3 ; 3 - регистр изменения данных
out dx.al ; внбор регистра изменения данных
bov dx,3cfH ; 3cf0 - порт дхя регистра данных
pop ax; ; в ах заносится значение roti
out dx.al ; al в регистр изменения данных
; Вычерчивание снмвоха ;
•,т»ишиигтит-,
pop сх; ; в сх заносится значение Ipl
up: bov al,[bx] ; чтение данннх в буферный регистр
bov al,es:[sij; похученяе данных дхя снмвоха
bov [bxj.al ; запись данных на экран
add bx.di ; адресуем обхасть памяти дхя
; схедувхей хинин экрана
56
inc si ; ннбяраем байт ди схедувдей гнннн в
loop tip ; вычерчиваемом символе
pop ax; ; в ах заносится значение rot?
out dx.al ; al в регистр изменения данных
pop ex; ; в сх заносится значение 1р2
id: aov al,[bx] ; этот цная (6 строя) аналогичен
aov al.es:[si] ; предыдущему (loop up)
lov [bxj.al
add bx.di
inc si loop ad
pop ax; ; в ах заносятся значение rot3
out dx.al ; al в регистр изменения данных
pop ex; ; dn: aov al,[bxJ в сх заносится значение Ipl
; этот цикл (6 строк) аналогичен
aov al.es:[si] ; предыдущему (loop up)
aov [bx],al
add bx.di
inc si loop dn
pop ds ; восстановление ds
ret ; возврат нз процедуры
scr_sii endp ; END конец процедуры scr_sia
Выход из программы осуществляется при нажатии клавиши ESC
(КЛЮЧ). Эксперименты с ней позволяют детально изучить работу ре-
гистра вращения.
Покажем, как определить цвет точки экрана. В адаптере EGA для
этих целей используются два способа: для первого в бит 3 регистра
режима (порт 3CF|6, индекс 5) записывается нуль, а для второго —
единица (с этой целью в регистр нужно послать 0 или 8). При первом
способе необходимо предварительно установить регистр выбора плана
(порт 3CF|6, индекс 4), соответствующий номер записывается в биты
О—1 (00, 01, 10, 11), а биты 2—7 не используются; результатом
является байт, содержащийся в выбранном плане по заданному
адресу. Для второго способа предварительно заполняется регистр
сравнения цвета (порт 3CFI6, индекс 2), в разряды 0—3 которого
необходимо записать код искомого цвета (биты 4—7 не используются);
после чтения содержимого планов по нужному адресу возвращается
байт с единицами для точек, имеющих указанный цвет. При сравнении
один или более битов кода цвета могут игнорироваться. Для этих целей
и используется регистр безразличия цвета (порт 3CFie, индекс 7),
у которого биты 0—3 соответствуют разрядам кода цвета, а биты 4—7 не
используются. Если в одном из битов 0—3 записан нуль, содержимое
соответствующего плана игнорируется.
Ниже приведен пример программы на языке СИ для определения
цвета точки по любому из описанных способов:
tinclnde <5tdio.h>
•include <dos.h>
•include <graphics.h>
void ffiainf)
{ int gd=DETECT,gn;
unsigned cbar s,color;
puts!"Укахнте цвет?");
scanf("%d“,&color);
57
initgraph(&gd,ign,""); /» мннцнаизацня график» X/
setcolorfcolor); /1 установка цвета colot «/
line(5,0,10,0); /» внчерчнваш гкннн из точки
х=5,у=0 В точку х=10,у«0 */
luuutttmnmittmmimttl
/i Пример настройки на способ 1 »/
/mtmtittiutmuuMtmtH/
oatportb(0x3CE,5); /» индекс регистра рехнна к/
oatportЬ(ОкЗС?,0); /» установка способа 1 »/
otitportb(0i3C£,4); /» индекс регистра выбора плана »/
outportb(ОлЗСР,0); /к выбор плана 0 »/
з = peekb(0xA000,0); /» чтение байта нз плана 0 »/
getch(); /» вахатъ лвбув ккавиву */
restorecrtnodef); /» переход в текстовой редки »/
printff"Способ 1: н - Хх\п",я);/* вывод значения s »/
if(s) putsfnxaH активен');
else patsCniaH не активен');
getchO; /» нахать на лсбув кяавниу »/
/tmmmitmittmmyitims/
/« Пример мастройкя на способ 2 »/
Itttmntttmuuunittauiti/
setgraphaode(l); /» возврат к графическое рехнму */
setcolorfcolor); /» установка цвета color »/
11ае(5,9,10,9); /» внчерчнванме линии нз точки
к=5,у-9 в точку х=10,у=0 к/
outportbfОхЗС?,5); /» индекс регистра рехнаа «/
o»tportb(0x3CF,8); /» установка способа 2 к/
outportbfОхЗСЕ,2); /» индекс регистра сравнения
цветов »/
oatportbfОхЗСЕ,2); /* код цвета 2 (0010) «/
outportbfОхЗСЕ,1); /» индекс регистра безразличия
цветов «/
outportbfОхЗСК,0xFE);/* так как бит 0 в нуле, выбираем
кода 2 (0010) и 3 (000) »/
з - реекЬ(0хй000,0); /» чтение байта из плана 0 »/
getchO;
closegraphO; /» завершение работн с графикой »/
printf("Способ 2: з -- Хх\п",в);/» вывод значения s «/
getchO; /> нахап яхбук кяавниу к/
]
Если задать цвет 1, то при первом способе будет возвращено
значение s= 7 и «план активен», а при втором способе s= О. Если задать
цвет 2, при первом способе s=O и «план не активен», а при втором способе
s=7. Цифра 7 получена потому, что цвет выбран для бит 2—О нулевого
байта заданного плана (функция line (5, О, 10, 0),. заполняет биты
2—О нулевого байта и 7—5 первого байта). Значение OOOOO111
дает 7.
Рассмотрим работу с адаптерами в текстовом режиме. Сначала пока-
жем, как выполняется сдвиг изображения на экране. Для этого произво-
дится пересылка данных из одной области видеобуфера в другую.
Ниже приведен пример программы на языках СИ и ассемблера, де-
монстрирующей циклический сдвиг изображения вправо и влево (для
режима 80X25 символов):
liaclede <stdio,h>
Haclude' <dos.h>
58
extern int iyasi6(int);
void >iain()
{ static unsigned 1st i,j;
puts("Сдвиг (вправо - 1, вдево - 0)!");
scant ("W ,4 j);
for(1=0;i(80;itt) {
»yas»6(j);
delay! 100); /» задерхка на 100 мнххнеекунд »/ ]
]
.MODEL SMALL ; объявление надой модели
.CODE ; сегмент кода
PUBLIC _дуа5»6 ; iyasi6, доступная из другого языка
jtyas»6 P50C ; натаю программы
push bp bov bp,sp ; значение Ьр помечается в стек
boy bx,[bp*4] ; в Ьх передается значение сдвига ; (вправо - 1, вхево - 0)
pop bp bov sx, 088000 ; восстанавливается значение Ьр
push es ; сохранение в стеке значений
push ds ; es н ds
bov es.ax ; установка в es н ds сегментного
boy ds,ax ; адреса экранной памяти
свр bx,1 ; если Ьх = 1, то сдвиг вправо,
je r ; если Ьх = 0, то сдвиг вдево
bov si,2 ; сдвиг нзобрадення на экране
boy di,0 ; вдево на 80 позицяй
jip ent ; переход к метке ent
r std ; установка флага направления
bov si,3998 ; сдвиг нзобрадення на экране
bov di,4000 ; вправо на 80 позиций
cnt’.Bov ex,2000 ; сдвиг выподняется ддя всех 2000
rep bovsy ; символов экрана
pop ds ; восстановление значений
pop es ; es и ds
ret ; возврат из процедуры
jyasa6 endp ; конец процедуры
END
В программу на языке СИ введена задержка, поэтому изображение
как бы вращается на экране.
Для обновления экрана можно также использовать страничный
режим. В области переменных BIOS по адресу 0:0462 хранится значение
активной (отображаемой в данный момент) видеостраницы. Поскольку
страницы в видеобуфере следуют непосредственно друг за другом (см.
табл. 2.2), небольшой фрагмент текста можно целиком поместить в
этой области. Далее текст можно перемещать по экрану без изменения
его местоположения в буфере. С этой целью в качестве стартового
адреса задаются различные точки в экранной памяти. При разрешении
80 X 25 символов добавление 80 к стартовому адресу сдвигает экран на
строку вверх, а вычитание 80 — на строку вниз.
Вычисленное значение необходимо поместить в регистр стартового
адреса (индексы 12, 13, порт ЗВ416 для монохромного режима и 3D4I6
для цветного) контроллера CRTC. Этот регистр не подсчитывает байты
атрибутов, поэтому адреса вычисляются не так, как при прямой
работе с видеобуфером. Индекс 12 соответствует старшему байту, а 13 —
младшему. Заметим, что адаптеры EGA/VGA не имеют микросхемы
CRTC 6845. Однако подобное устройство с расширенными возможностя-
59
ми реализовано в виде заказной микросхемы. В ней, в частности, со-
хранены многие регистры для адаптера CGA (ознакомиться с ними мож-
но по работе [3]). Отметим также, что CRTC сам пропускает разрывы
между страницами в экранной памяти (96 — для разрешения 80Х 25 сим-
волов и 48 — для разрешения 40X25 символов). BIOS хранит текущее
значение стартового адреса в двухбайтной переменной 0.-044Е (см.
табл. 1.3).
Ниже приведен пример программы на языке СИ, осуществляющей
аппаратный сдвиг экрана (с разрешением 80X25 символов) вниз (при
нажатии клавиши |) и вверх (при нажатии клавиши |); выход из
программы осуществляется после нажатия клавиши ESC (КЛЮЧ):
finclnde <stdio.h>
finclude <dos.h>
(include <Mos.h>
void main!)
{ unsigned sh - fl;
unsigned cbat stop, bbyte, Ibyte;
putsCUepenexeMe (1 - вверх, 2 - вниз, ESC - шод"):
»hile((stop - (bioskey(O) >> 8) 4 OxFF) != 1) {
/» ди выхода нз программ необходимо махать кхавхху ESC
со скэн-ходом 1 »/
if(stop 72) shtrOxSO;
/» 72 - скэн-код кдавнхх со стредкой вверх (при этом стар-
товый адрес увехмчавается на 0x50, т.е. на строку) »/
else if(stop == 80) sb-=0x50;
/» 80 - скэн-код кдавнхн со стреххой вниз (при этой стар-
товый адрес уиеньхаетсв на 0x50, т.е. на строку) »/
else printfI"\а”);
/t при неправшнои нахатнн вырабатывается звуковой сигнал в/
Ibyte : sb 4 ОхЕЕ; /в значение мхадвего байта в/
bbyte - (sb >> 8) 4 OxFF; /в значение стархего байта в/
outportb(0x384,12); /в выбор регистра 12 в/
outportb(0x385,bbyte); /в посылка стархего байта в/
outportb(0x384,13); /в выбор регистра 13 в/
outportb(0x3d5,Ibyte); ] /в посылка мхадвего банта в/
I
Рассмотрим теперь другие регистры CRTC. Первые 10 из них уста-
навливают режим работы дисплея (их лучше не трогать). Пары регист-
ров 10—11 и 14—15 задают форму и местоположение курсора, пара
16—17 содержит координаты светового пера. Регистр 20 задает линию
сканирования в строке символа для подчеркивания (при матрице 8Х 14
точек). «I
Каждая страница экрана (а их может быть до восьми) имеет
собственный курсор. Его позиция хранится в области переменных
BIOS по адресу 0:0450 (см. табл. 1.3). Восемь двухбайтных слов
позволяют задать местоположение курсора для восьми страниц. Бит 5
в регистре 10 CRTC отменяет курсор при установке в единицу и восста-
навливает его после сброса в нуль. Верхняя строка курсора называется
начальной, а нижняя конечной. Их номера хранятся в регистрах 10, 11
CRTC и в области переменных BIOS по адресу 0:0460 (первый байт —
значение конечной, второй—значение начальной строки).
В регистрах 14 и 15 CRTC хранятся текущие координаты
курсора. Они работают и на чтение, и на запись. При изменении
местоположения курсора необходимо одновременно устанавливать новые
значения в области переменных BIOS (адрес 0:0450).
60
Ниже приведен пример программы на языке СИ, изменяющей форму
курсора, устанавливающей его в средней части экрана (разрешение
80X25 символов) с выводом текста Новосибирск — Ульяновск — Минск
и перемещающей курсор на прежнее место. Каждое очередное действие
будет выполнено после нажатия любой клавиши:
^include <stdio.h>
tlnclode <dos.h>
void Bain()
[ unsigned bios_var;
getch();
biosjrar = peek(O,0x450); /* сохранение иестопохохе-
ння курсора BIOS в переменной bios_var »/
oatportb(0x3d4,10); /» выбор регистра 10 CRTC »/
outportb( 0x3d5, (1); /» запись начатой хинин курсора »/
oatportb(0x3d4,11); /* выбор регистра 11 CRTC »/
oatportb(0x3d5,12); /* запись конечной хинин курсора */
getcb(); /» нахать хкбув кхавнну »/
oatportb(0x3d4,14); /* выбор регистра 14 CRTC »/
oatportb(0x3d5,ОхА);/» запись координаты Т курсора »/
outportb(0x3d4,15); /» выбор регистра 15 CRTC »/
oiitportb(0x3d5,OxF);/* запись координата X курсора »/
poke(0,0x450,OxAOF);/* нзиененне переиенной BIOS */
print f( "Вовоснбнрск-Ухыновск-Кннск" );
poke(0,0x450,blosjrar); /» восстановиенне переиенной
BIOS »/
getchl); /» нахать хобуо кхавнну »/
]
При необходимости в программе можно отключить курсор и создать
его самому. Делается это путем изменения атрибута позиции, в которую
выводится символ (инверсное изображение, подчеркивание, мерцание и
т. п.). Адаптеры EGA/VGA позволяют разрешать или запрещать мерца-
ние. С этой целью для текстового режима в регистр 10;6 атрибутов
посылается значение 8 для разрешения и О для запрета. Следующий
регистр 11,6 позволяет устанавливать цвет за границей отображения
экрана (цвет бордюра). Его биты имеют такое же значение, как у ре-
гистров палитры.
В текстовом режиме символы выводятся на основании хранимой в
ПЭВМ информации об их начертании (из отдельных точек) в опреде-
ленной битовой матрице. Такие матрицы для адаптера CGA имеют
размер 8X8 точек, а для EGA/VGA они могут быть разными:
8X8, 8X14, 8X16, 9X14, 9X16 [20]. Адаптер CGA позволяет пользо-
вателю определять через вектор прерывания 1FI6 до 128 символов с но-
мерами от 128 до 255. Для адаптера EGA их число увеличено до 1024, из
них одновременно доступно 512. В случае матрицы 8Х 8 данные для каж-
ного символа содержатся в восьми байтах. Символ как бы состоит из
восьми полосок, а указанные байты задают расположение точек в каждой
из них (если в некотором бите единица, то соответствующая точка
высвечивается на экране). Адрес начала массива, состоящего из байтов
такого вида (сегментный адрес и смещение), сообщается процедурам
BIOS, которые перестраивают адаптер на отображение требуемых
символов.
В адаптерах EGA/VGA при инициализации текстового режима
таблица с описанием символов копируется в план 2 экранной памяти,
который разделяется на блоки по 8 К байт каждый. Стандартный набор
символов из ПЗУ. BIOS видеодоступа помещается в блок 0. При налн-
61
Таблица 2.3
Г рул па Порт (индекс) Режимы ;> 64 К
0 1 2 3 4 5 (> 7 D E E 10 I 10
I 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Внешние ЗС2 23 23 23 23 23 23 23 А6 23 23 А2 А7 регистры Регистры ЗС5(0) w 03 03 03 03 03 03 03 03 03 03 03 03 секвенсора ЗС5(1) w 06 06 01 01 OB 0В 01 00 ОВ 01 05 05 ЗС5 2) w 03 03 03 03 03 03 01 03 OF OF OF OF 3C5(3 w 00 00 00 00 00 00 00 00 00 00 00 00 3C5(4) w 03 03 03 03 02 02 06 03 06 06 00 00 Регистры 3?5(1) 27 27 4F 4F 27 27 4F 4F 27 4F 4F 4F CRTC 3?5(2) 2D 2D 5C 5C 2D 2D 59 59 2D 59 56 53 * 2 В 2B 53 53 3?5(3) 37 37 2F 2F 37 37 2D ЗА 37 2D 1A 17 ЗА 37 3?5(4) 31 31 5F 5F 30 30 5E 51 30 5E 50 50 50 52 3?5(5) 15 15 07 07 14 14 06 60 14 06 EO BA 60 00 3?5(6) ° 04 04 04 04 04 04 04 70 04 04 70 6C * 6C 6C 6C 6C 3?5(7) 11 11 U 11 И И И IF И И IF IF * IF IF IF IF
Продолжение табл. 2.3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
3’5(8) 00 00 00 00 00 00 00 00 00 00 00 00 3?5(9) 07 07 07 07 01 01 01 0 D 00 00 00 00 * 0D 0D 0D 0D 3’5 (А) 06 06 06 06 00 00 00 0В 00 00 00 00 3?5(В) 07 07 07 07 00 00 00 ОС 00 00 00 00 3?5(10)w El El El El El El EO 5E El EO 5E 5F »(r) 5E 5E 5E 5E 3?5(ll)w 24 24 24 24 24 24 23 2E 24 23 2E 26 * 26 26 26 26 3’5(11)r 3?5(12) C7 C7 C7 C7 C7 C7 C7 5D C7 C7 5D 5D 3?5(13) 14 14 28 28 14 14 28 28 14 28 14 14 28 28 3’5(14) 08 08 08 08 00 00 00 OD 00 00 OD OF * OF OF OF OF 3?5(15) EO EO EO EO EO EO DF 5E EO DF 5E 5F * 5E 5E 5E 5E 3’5(16) FO FO FO FO FO FO EF 6E FO ЕЕ 6E OA * OA OA OA OA 3?5(17) АЗ АЗ A3 A3 A2 A2 C2 A3 E3 E3 8B 8B ЕЗ E3 3?5(18) FF FF FF FF FF FF FF FF FF FF FF FF Регистры гра- 3CA 01 01 01 01 01 01 01 01 01 01 01 01 фического Конт- ЗСС 00 00 00 00 00 00 00 00 00 00 00 00 роллера 3CF (0) 00 00 00 00 00 00 00 00 00 00 00 00
Продолжение табл. 2.3
1 2 3 4 5
3CF(1) 00 00 00 3CF(2) 00 00 00 3CF(3) 00 00 00 3CF(4) 00 00 00 3CF(5) 10 10 10 Регистры 3C0(0—F) 00 атрибутов 01 02 03 04 05 (6) 06 (6)* 14 07 (8) 10 (8)* 5 38 (9) И (9)* 39
6 7 8 9 10 11 12 13 14 15 16
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00
10 30 30 00 10 00 00 10 10 00 00
00 00 00 00 00 00
13 17 08 01 08 01
15 17 08 02 00 02
17 17 08 03 00 03
02 17 08 04 18 04
04 17 08 05 18 05
06 17 08 06 00 14
07 17 08 07 00 07
10 17 10 10 00 38
11 17 18 11 08 39
3 Скляров
Окончание табл. 2.3
I 2 3 4 5 6 7 8 9 10 1 1 12 13 14 15 16
Примечания: (А) 12 12 17 18 12 00 ЗА (А)* ЗА (В) 13 13 17 18 13 00 ЗВ (В)* ЗВ (С) 14 14 ' 17 18 14 00 ЗС (С)* ЗС (D) 15 15 17 18 15 18 3D (D)* 3D (Е) 16 16 17 18 16 00 ЗЕ (Е)* ЗЕ (F) 17 17 17 18 17 00 3F (F)* 3F ЗС0(10) 08 08 08 08 01 01 01 0Е 01 01 0В 01 ЗС0(12) OF OF OF OF 03 03 01 OF OF OF 05 05 3C0(13) 00 00 00 00 00 00 00 00 00 00 00 00 1. Символ «*» означает изменение установок для расширенного цветного дисплея (RGBrgb 05 OF
2. Символ «?» означает, что выбирается буква В для монохромного дисплея и D — для цветного.
3. г—режим (w—только запись, г — только чтение).
4. (г) — установки по умолчанию не соответствуют режиму чтения.
5. Графы 15, 16 следует рассматривать при объеме экранной памяти более 64 К байт.
6. Все числа в таблице— шестнадцатеричные.
7. В графах 3—14 правые незаполненные столбцы имеют те же значения, что и ближайший левый столбец.
чип у адаптера достаточной памяти могут быть объявлены еще три блока.
Используемый блок задается битами 0—3 регистра с индексом 3 (порт
ЗС5|б). Биты 1—0 указывают номер блока, который выбирается, если
бит 3 и интенсивности в коде атрибута для отображаемых символов ра-
вен нулю, а биты 3—2— если он равен единице. Когда установка обеих
пар битов совпадает, нельзя использовать два набора символов, и бит 3
кода атрибута изменяет интенсивность свечения экрана дисплея. Таким
образом, могут быть одновременно доступны либо 256, либо 512 симво-
лов. После изменения стандартного набора знаков можно в любой мо-
мент восстановить прежние значения из ПЗУ.
Обслуживание видеомониторов на уровне BIOS осуществляется
посредством прерывания 10,6 (16). Соответствующие вопросы будут под-
робно рассмотрены в гл. 12.
В табл. 2.3. сведены начальные установки (по умолчанию) раз-
личных регистров для адаптеров EGA/VGA (выполненные средствами
BIOS), обобщенные по результатам работы [16].
2.3. НАКОПИТЕЛИ НА ГИБКИХ И ЖЕСТКИХ ДИСКАХ
Магнитные диски служат для организации внешней
памяти, которая используется для длительного хранения
больших объемов информации, не разрушаемой при вы-
ключении напряжения питания ПЭВМ.
Гибкий магнитный диск — дискета — представляет со-
бой круглую гибкую пластину, покрытую магнитным мате-
риалом. Она помещена в квадратный предохранительный
корпус (рис. 2.4), имеющий 4 отверстия. Центральное
отверстие предназначено для захвата диска приводом дис-
ковода. Продолговатая прорезь необходима для доступа
головок записи-чтения. Отверстие в корпусе позволяет на-
ходить индексное отверстие на диске, которое использу-
ется для указания начала и конца дорожки. Квадратная
прорезь на краю корпуса служит для защиты записи. Если
она открыта, то запись может выполняться, если закры-
та,— нет.
Данные на дискете размещаются по дорожкам, пред-
ставляющим собой замкнутые концентрические окружно-
сти. Каждая из них расположена на определенном рас-
стоянии от центрального отверстия. Дорожки делятся на
части, которые называются секторами и представляют
основную единицу хранения информации. При обращении
к НГМД всегда записывается или считывается целый
сектор, независимо от объема запрашиваемой инфор-
мации.
Данные могут размещаться как на одной стороне
дискеты, так и на двух. Эти стороны нумеруются цифрами
0 и 1. Каждая из них имеет 40 или 80 дорожек с номерами
от 0 до 39 либо от 0 до 79. Любая дорожка содержит 8,9, 15
66
Рис. 2.4. Структура гибкого магнитного диска
или 18 секторов с номерами от 1 до 8, от 1 до 9, от 1 до 15
или от 1 до 18. Нулевая дорожка размещается ближе
всего к внешнему краю дискеты. У двухсторонних дискет
за последним сектором нулевой стороны следует первый
сектор той же дорожки, но первой стороны. Как при
одностороннем, так и при двухстороннем формате за по-
следним сектором одной дорожки идет первый сектор
следующей дорожки.
Важной характеристикой диска является плотность за-
писи. При записи 40 дорожек данных на поверхности
диска плотность считается двойной, при записи 80 доро-
жек — четверной. Двойная плотность составляет 48 доро-
жек на дюйм (дюйм равен 25,4 мм), а четверная — 96
дорожек на дюйм. Размер сектора для диска диаметром
133,4 мм, поддерживаемый средствами BIOS, может со-
ставлять 128, 256, 512 и 1024 байта (в операционной
системе MS-DOS используется размер 512 байт).
Существует два способа разметки дорожек на секторы:
фиксированный, или аппаратный, и программный. Для ма-
67
шин семейства IBM / PC расположение дорожек на диске и
число сторон определяются характеристиками НГМД и по
существу являются неизменными. Однако количество сек-
торов на дорожке и их размер можно задать программно
в процессе форматирования.
В машинах семейств IBM/PC, PS/2 преимущественно
используются:
1) 5,25-дюймовые гибкие диски, позволяющие хранить
360 К байт (2 стороны, 9 секторов, 40 дорожек) и 720 К
байт (2 стороны, 9 секторов, 80 дорожек) информации;
2) 5,25-дюймовые гибкие диски, позволяющие хранить
1,2 М байта (2 стороны, 15 секторов, 80 дорожек)
информации;
3) 3,5-дюймовые плоские жесткие диски, позволяющие
хранить 1,44 Мбайта (2 стороны, 18 секторов, 80 дорожек)
информации. Их толщина приблизительно такая же, как у
двух гибких дисков, а диаметр в 1,5 раза меньше.
Накопители на жестких магнитных дисках (винчесте-
ры) характеризуются собственными форматами данных.
Любой такой диск имеет физический и логический формат.
Физический формат определяет размер сектора (в бай-
тах), число секторов в цилиндре (все дорожки, располо-
женные на одном расстоянии от центра, образуют ци-
линдр), число цилиндров и число сторон. Логический
формат характеризует способ организации информации.
Например, часто используется диск объемом 20 М байт
(4 стороны, 17 секторов, 615 цилиндров).
Жесткие диски имеют определенный физический фор-
мат, который устанавливается в процессе изготовления
диска. Логическая структура жесткого диска’ задается
программистом, причем это должно быть сделано до его ис-
пользования ОС. Установка логической структуры осуще-
ствляется в два этапа. Во-первых, диск можно разделить
на части (до четырех), каждую из которых может исполь-
зовать своя операционная система. Затем каждую из этих
частей необходимо сформатировать в соответствии с тре-
бованиями той системы, для которой она предназначена.
Например, физический диск объемом 20 М байт можно
разделить на 4 логических диска объемом 5 М байт каж-
дый.
Данные на дисках не могут записываться и считы-
ваться произвольно. Необходимо их обрамление специаль-
ными метками. Такое обрамление называется форматиру-
ющим. Поэтому новые диски до их использования должны
быть отформатированы утилитой FORMAT ОС. Основная
68
часть процесса форматирования — запись адресных ме-
ток, идентифицирующих каждый сектор и указывающих
его размер.
Рассмотрим, как размещается информация на гибком
магнитном диске. Первый сектор любой форматируемой
дискеты содержит программу-загрузчик, которая исполь-
зуется для запуска ОС. Затем идут секторы, содержащие
таблицу размещения файлов (ТРФ). Ее структура будет
рассмотрена далее. Справочные данные о различных
дисках сведены в табл. 2.4 (эту таблицу можно рас-
сматривать только как ориентировочную; уточняющие
сведения по этому вопросу будут даны в гл. 3). После
Таблица 2.4
Объем диска, М байт Количество Нам альный сектор данных Количество секторов Формат диска
секторов в каталоге элементов в каталоге в кластере в ТРФ
0,16 4 64 9 1 1 FE
0,18 4 64 9 1 1 FC
0,32 7 112 15 2 2 FF
0,36 7 112 15 2 2 FD
1,20 14 224 29 1 7 F9
1,44 14 224 33 1 9 F0
20 Для жесткого диска здесь 4 40
задаются переменные зна-
чения
основной ТРФ следует копия ТРФ (вследствие важного
значения соответствующей информации). И, наконец, да-
лее следует файл с корневым директорием. Все остальные
секторы используются для хранения данных.
Корневой директорий включает список всех файлов на
дискете. Его элементы содержат всю информацию о файле,
за исключением сведений о размещении файла, кото-
рые хранятся в ТРФ. Любой элемент имеет длину 32. бай-
та и включает восемь полей (все они выравниваются
по левой границе; пустые байты заполняются пробе-
лами) :
1) имя файла — 8 байт. Если первый байт имеет значе-
ние Е516, то этот элемент не используется; если он имеет
значение 2Е|6, то этот элемент указывает на директорий
нижнего уровня;
2) расширение имени файла — 3 байта;
3) атрибут — 1 байт. Используется для установления
признака «только чтение» (нулевой бит), скрытого файла
69
(первый бит), системного файла (второй бит), признака
метки тома (третий бит), признака поддиректория (чет-
вертый бит), признака архивного файла (пятый бит).
Шестой и седьмой биты этого байта — резервные. Если
задан признак метки тома, то этот элемент содержит не
ссылку на файл, а имя диска, которое занимает первые
11 байт. Архивный бит используется утилитами BACKUP
и RESTORE (см. об этом в гл. 3);
4) зарезервированное поле для возможного использо-
вания в будущем — 10 байт;
5) время — 2 байта. Здесь хранится время создания
или последней модификации файла. Первые 5 бит занима-
ют часы, вторые 6 — минуты, третьи 5 — секунды. В по-
следнем поле каждая единица соответствует двум секундам;
6) дата — 2 байта. Здесь хранится дата создания или
последней модификации файла. Первые 7 бит занимают
годы, которые отсчитываются от числа 1980 (от 1980 г.),
вторые 4 — месяцы и третьи 5 — дни;
7) номер начального кластера — 2 байта. Начальный
кластер является первой частью пространства данных в
файле на дискете;
8) объем файла — 4 байта. Наличие таких сведений
вызвано тем, что файл обычно частично занимает послед-
ний отведенный ему кластер, а здесь указывается его
точная длина.
Существуют два типа директориев: корневые (см.
выше) и нижнего уровня (поддиректории). Директорий
нижнего уровня является дополнением к корневому и мо-
жет храниться как обычный файл в любом месте на диске-
те. Форматы его полей такие же, как и для корневого
директория, разница лишь в том, что размер директория
нижнего уровня не ограничен.
Процедура распределения пространства памяти на ди-
скете между файлами реализуется с помощью ТРФ.
Каждый элемент ТРФ размером 12 бит (MS-DOS под-
держивает также размер 16 бит) соответствует одному
кластеру, или фрагменту дискового пространства, выделя-
емого файлу. В нем указываются признаки занятости
кластера, перехода между кластерами, окончания файла.
Свободным кластерам соответствуют нулевые значения
(00016) элементов таблицы. Участки пространства на ди-
скете, принадлежащие файлу, соединены в цепочку. Эле-
мент директория файла (поле «Номер начального класте-
ра») содержит номер элемента в ТРФ, который соответст-
вует первому кластеру в цепочке. Этот элемент в ТРФ
70
содержит номер следующего кластера в цепочке и т. д.,
пока не будет достигнут конец файла (признак конца —
одна из цифр FF816—FFF|6). Для дефектных кластеров
задаются значения FF7|6, а для резервных — от FF0i6 до
FF7i6. Первый кластер данных имеет номер 2 — это озна-
чает, что первые два элемента ТРФ не используются для
хранения информации о размещении файла. В них указы-
ваются сведения о формате дискеты (байт 1), которые да-
лее используются управляющими программами (см. табл.
2.4). Кластерам 2 и 3 соответствуют байты 3—5 (один эле-
мент занимает 1,5 байта) и т. п.
При записи на дискету файла для него по одному
выделяются свободные кластеры (выбирается первый
свободный кластер с наименьшим номером). При этом вся
информация файла не будет храниться в одной непрерыв-
ной области диска. Файл оказывается как бы «размазан-
ным» по дискете. Когда файлы копируются на новую
дискету, их расположение становится экономичным. Если
же удаляются или создаются какие-либо данные, разме-
щение информации на дискете становится запутанным.
Жесткие диски содержат главную запись загрузки,
включающую таблицу разделов, которая дает возмож-
ность распределить диск между несколькими ОС. В табли-
це разделов находятся сведения о том, какой первый
сектор содержит программу-загрузчик и где на диске начи-
нается ОС. В остальном организация жестких дисков ана-
логична организации гибких дисков.
Охарактеризуем аппаратные средства, используемые в
ПЭВМ для работы с магнитными носителями инфор-
мации. Для управления электродвигателем и головками
накопителя на дискетах применяется микросхема контрол-
лера НГМД 765 фирмы NEC (аналогичным устройством
является микросхема 8272А фирмы Intel). Один контрол-
лер позволяет обслуживать до четырех накопителей. Про-
граммировать его приходится только тогда, когда необ-
ходимо предусмотреть средства защиты от копирования
дискет. При нормальной работе все необходимые операции
выполняют процедуры BIOS и ОС. ПЭВМ IBM PC/XT
содержит один контроллер, взаимодействие с которым осу-
ществляется через порты 3F016—3F7[6 (см. табл. 1.4), а
модель АТ — два контроллера (порты второго устройства
37016—37716).
Контроллер может выполнять до 15 операций: поиск
дорожки, чтение и запись одного сектора, форматирова-
ние дорожки, перекалибровку диска, определение статуса
71
накопителя и т. п. Чтение файла включает его поиск в
каталоге, определение его места на диске (с помощью
ТРФ) и выполнение операций чтения каждого его сектора.
Для этого необходимо: включить электродвигатель при-
вода и подождать, пока он наберет требуемую скорость
вращения; найти нужную дорожку и ждать сигнала завер-
шения этой операции (он вырабатывается и направляется
на вход IRQ6 контроллера прерываний); выполнить
инициализацию контроллера прямого доступа к памяти
(ПДП)для пересылки данных в ОЗУ; передать контролле-
ру дискет команду для чтения и ожидать поступления
сигнала IRQ6, указывающего, что пересылка данных за-
вершена; получить сведения о статусе контроллера дискет;
выключить электродвигатель привода.
Основными портами первого контроллера НГМД яв-
ляются: 3F2>fl— регистр цифрового вывода, работающий
только на запись (биты 1—0: выбор накопителя — 00—А,
01—В, 10—С, 11—D, для модели АТ бит 1 не используется;
бит 2:1 —разрешение работы контроллера, 0 — сброс
контроллера; бит 3: 1 —разрешение работы устройства
ПДП и выработки прерывания; биты 7—4: включение
электродвигателя — 0001—А, 0010—В, 0100—С, 1000—D,
для модели АТ биты 6, 7 не используются); 3F4i6— ре-
гистр статуса, работающий только на чтение (биты 3—0:
накопитель занят — 0001—А, 0010—В, 0100—С, 1000—D,
для модели АТ биты 2, 3 не используются; бит 4: 1 — кон-
троллер занят операцией чтения или записи; бит 5: 0—
режим ПДП установлен, 1 — режим ПДП сброшен; бит
6: 1 — готовность к приему данных, 0 — готовность к пе-
редаче данных; бит 7: 1 — контроллер готов к приему/
передаче команд или данных); 3F516 — регистр команд/
данных, работающий и на чтение, и на запись. В качестве
кодов команд используются: 0F[6 — поиск дорожки; 66te —
чтение данных; 4516 — запись данных; 4D16 — формати-
рование; 0716 — перекалибровка; 04i6 — определение ста-
туса накопителя.
Перекалибровка предполагает возврат головки на ну-
левую дорожку. Контроллер следит за текущей позицией
головки. Когда происходит его сброс (установкой в нуль
бита 2 регистра 3F2i6), значение текущей позиции уста-
навливается в нуль, независимо от того, где находится
головка на самом деле. В результате возникает необхо-
димость перекалибровки (эта операция выполняется очень
редко и только при серьезных ошибках накопителя).
В определенный момент времени контроллер может
72
иметь доступ только к одному накопителю, но электро-
двигатели могут быть включены и у нескольких устройств.
Обычно они остаются включенными в течение нескольких
секунд после завершения операций. Это позволяет снизить
потери времени на разгон электродвигателя. Однако остав-
лять его включенным постоянно нельзя, так как это
приведет к преждевременному износу дискет.
Работа контроллера НГМД делится на три этапа:
1) командный, на котором устанавливается необходи-
мая последовательность действий;
2) основной, на котором производятся все необходи-
мые действия, предписанные командой;
3) результирующий, на котором анализируется пра-
вильность выполнения команды путем считывания и про-
смотра байтов статуса.
На первом этапе в контроллер посылается некоторая
строго фиксированная последовательность байтов. На пер-
вом и третьем этапах необходимо следить за тем, чтобы
число считываемых или передаваемых байтов было пра-
вильным. Это число меняется в зависимости от выпол-
няемой операции (коды операции были приведены выше).
Первым байтом является код операции (команды). В боль-
шинстве случаев второй байт содержит номер накопителя
(00, 01, 10, 11) в битах 1 —0 и номер головки (0, 1) в бите 2.
Остальные биты не используются. Для операции поиска
дорожки далее требуется еще один байт, в котором указы-
вается номер дорожки. Чтение или запись требует семи
дополнительных байтов (всего их 9): байт 3—номер
дорожки; 4 — номер головки; 5 — номер сектора; 6 — чис-
ло байтов в секторе (0—128, 1—256, 2—512, 3—1024);
7 — номер последнего сектора на дорожке; 8 — длина
сдвига; 9 — длина данных. Последние четыре байта хра-
нятся в специальной таблице, на которую указывает
вектор прерывания lEie- Они расположены, начиная со
смещения 3, в том порядке, в котором их следует передать
контроллеру НГМД.
Прежде чем пересылать или считывать байт из регист-
ра данных (порт 3F516), необходимо убедиться в его го-
товности. Для этого анализируются значения битов ре-
гистра статуса. Когда байт посылается в регистр данных,
бит 7 статуса устанавливается в нуль. Операцию необ-
ходимо повторять до тех пор, пока этот бит не станет рав-
ным единице. Затем можно посылать следующий байт.
После завершения любой операции (например, поиска
дорожки) контроллер НГМД вырабатывает сигнал IRQ6.
73
В ответ на него процедура обработки прерывания BIOS
устанавливает бит 7 байта статуса в области переменных
BIOS по адресу 0:043Е (см. табл. 1.3). Можно проверять
этот байт до тех пор, пока бит 7 не окажется в единице, и
затем выполнять следующее действие.
Рассмотрим процедуру начальной настройки (инициа-
лизации) блока ПДП, который управляет обменом данны-
ми между периферийными устройствами и ОЗУ ПЭВМ без
участия МП. ПЭВМ IBM PC/XT использует одну четы-
рехканальную микросхему Intel 8237А. Канал 0 предназ-
начен для регенерации динамической памяти. Канал 1 до-
ступен для дополнительно подключаемого оборудования.
Канал 2 обеспечивает работу с контроллером НГМД. Канал
3 работает с контроллером жесткого диска. Модель АТ
содержит второй контроллер 8237А (каналы 4—7). В ре-
зультате допускаются операции обмена типа память —
память, что существенно увеличивает производительность
ПЭВМ.
Перед инициализацией канала (в нашем случае его
номер 2) необходимо передать в контроллер ПДП код вы-
полняемой команды (для чтения — 4616, для записи —
4А16). Он посылается в порты OBie (биты 1—0: номер
канала — 00—0, 01 — 1, 10—2, 11—3; биты 3—2: тип пере-
дачи — 00— проверка, 01 — чтение, 10 — запись; бит 4:
1 — разрешение автоматической инициализации; бит 5:
приращение адреса +1 — 1 и —1 — 0; биты 7—6: режим
обмена — 00— по запросу, 01 — по байту, 10 — по блоку,
11—каскадный) и 0С[6, работающие только на запись.
Каждый канал контроллера ПДП содержит три реги-
стра. Первые два для канала 2 имеют адреса портов 0416 и
8116 (для каналов 1, 3: 02[6 и 8316, 0616 и 82ie) - В них
заносится адрес буфера ОЗУ, с которым будет происхо-
дить обмен данными. Этот адрес 20-разрядный и вычи-
сляется умножением сегментного адреса на 16 и прибавле-
нием смещения (например, 2222:1234 дает 23454i6). Пра-
вые четыре цифры (в примере — 3454) посылаются в порт
0416 (сначала младший байт, потом старший), оставшиеся
цифры (в примере — 2) — в порт 81 ie- Заметим, что в этот
порт для XT посылаются только 4 бита (одна шестнад-
цатеричная цифра), а модель АТ может принимать и 8 бит.
Третьим регистром канала блока ПДП является 16-раз-
рядный счетчик, исходное значение которого (при задании
декремента) должно быть на единицу меньше числа пере-
даваемых данных. Для канала 2 доступ к счетчику осу-
ществляется через порт 05^ (для других каналов: 1—0316,’
74
3—07|6). В него нужно передать два байта (сначала
младший).
После установки всех трех регистров необходимо раз-
решить работу выбранного канала (для нашего случая —
2). С этой целью в порт OAie (биты 1—0: выбор канала —
00—0, 01 — 1, 10—2, 11—3; бит 2: 1 —установка маски
для канала, 0 — очистка маски, т. е. разрешение работы
канала; биты 7—3 не используются) необходимо пере-
дать значение 2. В результате блок ПДП будет ожидать
данные от накопителя. Далее необходимо сразу же пере-
дать командные байты в контроллер НГМД.
После завершения операций пересылки из контроллера
НГМД могут быть считаны байты статуса. В случае чте-
ния и записи их семь: байт статуса 0; байт статуса 1; байт
статуса 2; номер дорожки; номер головки; номер сектора;
количество байтов на сектор (в рассмотренном выше коде
от 0 до 3). Если передать в контроллер НГМД
команду 0416 и следом за ней байт с номером накопителя
(биты 1—0) и головки (бит 2), то можно получить еще
один байт статуса, единичные значения битов которого
интерпретируются следующим образом: бит 7 — ошибка
накопителя; бит 6 — диск защищен от записи; бит 5 —
отсутствие готовности накопителя; бит 4 — неизвестна те-
кущая позиция головки; бит 3 — двухсторонний диск; бит
2 — номер головки; биты 1—0 — номер накопителя. Байты
статуса помещаются в область переменных BIOS, начиная
с адреса 0:0442 (см. табл. 1.3). По адресу 0:0441 хранится
еще один байт статуса диска, который может содержать
следующие значения: 8016 — отсутствует ответ на под-
ключение накопителя; 4016 — неудача операции поиска;
2016 — ошибка контроллера НГМД; 10i6 — ошибка при
чтении; 0916 — попытка доступа за границу 64 К байт;
0816 — переполнение блока ПДП; 04;6 — сектор не найден;
02,6 — адресная метка не найдена; 01,6 — в контроллер
НГМД послана неверная команда.
Работа с жестким диском ведется аналогично.' Для
ПЭВМ семейства IBM PC/XT к портам для таких дисков
относятся 320,6—32716, а для модели АТ— IFOie—1F7i6
(контроллер 1) и 17016 — 177,6 (контроллер 2). Контрол-
лер XT вырабатывает аппаратное прерывание IRQ5 после
каждой операции (чтение, запись и т. п.), а в модели
АТ— IRQ14. Сигналу IRQ5 соответствует вектор преры-
вания 0Di6, a IRQ14 — 76,в.
В заключение рассмотрим пример работы с контроллерами НГМД
и ПДП на нижнем уровне. Соответствующая программа написана
75
на языке СИ и позволяет считать информацию в выделенный буфер из
сектора 5 дорожки 30 стороны 0 гибкого магнитного диска А. Получен-
ные данные затем выводятся из буфера на принтер. Кроме того, из
контроллера НГМД считываются и отображаются на экране дисплея все
8 байт статуса:
/ttttttttttttttttttttttttttttttttttttttttttttttttttt/
/» Ерограииа ди работы с говтроалераия ВГМД а ЕДЯ »/
/tttttttttttttttttttttttttttttttttttttttttttttttttttf
7include (stdio.h)
Iinclude <dos.h>
ginclade (alloc.h>
void uial)
[ unsigned char »bnf; It увазатель aa брфер дли даавил
от иаюпитеаа »/
int 1; I* japaoianaaa аеремеаааа цаиа »/
long addrjaf; /» физический адрес дли контроллера
HI»/
unsigned h_buf; /» hj>nf - crapaaa вестаадцатерачааа
цифра адреса буфера »/
unsigned Lbnf; /» Lbnf - четыре мдадие аестаад-
цатерачаке цафры адреса буфера »/
unsigned s_es,zj>x, It сегаеат а смецеаае дда таблицы
аараиетров гибкого диска »/
unsigned char status!); /» фуигцяя дда чтеиаа баИов
состоаааа аоатроддера ВГЦ »/
void ngadl); /» функция два передача байта
в контроллер НГМД »/
unsigned char wait_bit7(); It фршцаа ондааиа установка
в едааацр бита 7 регистра статуса »/
bnf = (unsigned char»)aalloc(512); It буфер для чтеааа »/
It ввчасаеове физичесвого адреса буфера дда контроллера ИДО »/
addrjnf - 16L » (long)FPJ5K(bnf) 4 (long)FPJ)FF(buf);
h.bnf - addrjnf >> 16;/* поарчеаае cvapaei цяфри буфера »/
IJinf - addr_buf S OxFFFF; /< подрчевне четирех андааа
цифр буфера »/
liwttttttttttttttttttttttttttttttti
It Включение электродвигатели ПГИД »/
/mtnttttttttttttttttttttttttttttt/
outportbf0x3F2,OxlC); /» вклачение электродвигатели
диска А: »/
delay!450);It олндание приблизительно 0,5 с дли
разгона электродвигатели »/
inttnttttttttttttttttttttttttttttttl
It Установка иагнитиод годовав НГМД »/
inttttttttttttttttttttttttttttttttttl
ngad(OxF); It F - аоиер кода команды дав поиска »/
ngad(O); It 0 - номер накопители (А) »/
ngad(30); /t 30 - аоиер доролди Ч
aaitj>it7(); /» охидание установки в единицу бита 7
регистра статуса контроллера ПГКД »/
dela;(225); /» время установки головки »/
inttttttttttttttttttttttttttttttti
It нннциалязацяя контроллера ПДП »/
ltt»ttttttttttttttttttttttttttmi
outportb(0xB,0x46); It код чтение 0x46 поптроиера ОДО V
outportb(OxC,Ox46); /> необходимо дослан в порты В и С */
It четнре яладине цифры адреса буфера в воптроиер ОДО
76
(сначала иладжий, потом старми» байт) »/
outport6(0x4,(unsigned char}l_buf I OzFF);
outporib(0x4,(unsigned char)((l_bnf 4 OxFFOO)>>8}};
/» старнан цифра адреса буфера а контролер ПДП »/
outportb(0x81,(nnsigned cbarlhjnf 4 OxF);
/« установка значении счетчика а ПДП 4/
outportb(0x5,0xFF); /» передача идаддего байта »/
ontportbl0x5,1); /» передача старшего байта »/
outportb(0xA,2); /» контролер ПДП ондает даяние »/
/tiiittttwtuttttttttttttttttttttttttttttttttttttttttti
/4 Получение таблицы параметров ди гибкого магнитного 4/
/4 диска; 0х1Е - указатель на таблицу параметров дхя 4/
/» диска 4/
/4444444444444444441444444444444444444444444414444444444/
JL: 0x11; /х помер вектора, указваацего на табпцу */
JB р 0x35; /4 Функция ОС для нолучевня вектора 4/
geninterrnpt(0x21); /4 внзов прериваиия 0x21 */
г_Ьх - JI; /4 сведение таблицы параметров диска 4/
г.ез - JS; /4 сегмент таблицы параметров диска »/
/*****4444444444444444444444*444444444444444444444444/
/4 Установка параметров чтении дли контроллера ПГИД 4/
/******* 4 4444 4 4 4 44444 44 4 4 4 4444444 444444 4444 4 444444444/
ngad(0x66); /4 66 - команда чтении 4/
ngad(OxO); /4 номер головки (0) и накопители (0-А) 4/
ngad(30); /» номер доролкн (30) 4/
ngad(O); /4 номер головка (0) 4/
ngad(5); /4 номер сектора (5) */
ngad(peekb(zjs,z_bxt3)); /4 код размера сектора (для
512 байт здесь будет 2) 4/
ngad(peekb(a_es,х_Ьхт4)); /» номер последнего сектора
на доролке ’/
ngad(peekb(z_es,z_bx+5)); /4 длина сдвига аз таблицы */
ngHd(peekb(z_es,z_bxT6)); /4 длина данянл нз таблнцн 4/
wait_bit7(); /» аналогично рассмотренному вине 4/
/4*444444444444444444444444444444444444444444444444444/
/4 Вывод байтов статуса (состояния коптроллера НГМД) 4/
/«4444444444444444444444444444444444444444444444444444/
printf("Байт статуса 0: k2x;\n",statns());
printf("Байт статуса 1: Х2х;\п",statnst));
рг!п1Г(”Байт статуса 2: *2х;\п",statns());
рг!пК("Помер дорохки: Л2х;\п‘,status());
printf("Помер головки: Х2х;\п",status!));
printf("Помер сектора: Х2х;\п",statnst));
printf('6aiTOB на сектор: Д2х (для 512 байт '
"внводитси код 2);\п",statnst));
/4 восьмой байт статуса 4/
ngad(0x4); /» 4 - команда чтении статусаД/
Hgad(OxO); /* номер головки (0) и накопители (0-А) 4/
prlntf("6a#T статуса 3: Х2х.\п",statnst));
/*4***444444*444444444444444444444*44/
/4 Выключение электродвигатели ПГЦД 4/
/***** 4 4 4444 4 4 4 44444 44 4 444444444 4* 4*4/
outportb(0x3F2,0xC); /* внклвчение электродвигателя 4/
/****4444444444*444444444444444444444444/
/4 Внвод содерхниого буфера на нрннтер 4/
/****44444444444444444444444444444444444/
for(i=0; i<512; 1Н)
fprintf(stdprn, "Байт X3d Xx;Xc", 1,bnf[i],
77
)
/tttttttttttttttttttttttttttttttttttttttttttttttt/
It Фунгцяя jia передачи байга а контролер 8ГЦ tf
/tttttttttttttttttttttttttttttttttttttttttttttttt/
void ngad(unsigned char bbyte)
( while!(inportb(0x3F4) 4 0x80) -- 0);
it nocie того, как бит 7 регистра статуса будет в единице
передача байга и порт 0x375 »/
ontportb(0x3?5, bbyte);
Itttttttttttttttttttttttttttttttttttttttttttttttttttt/
It Функция чтения байтов состояния контроллера НГМД я/
/ttttttttttttttttttttttttttttttttttttttttttttttttttttl
Hnsigned char status!)
[ while!(inportb(0x3F4) 4 0x80) --- 0);
It после того хак бит 7 регистра статуса будет в единице,
внноаняется чтение и возврат очередного байта состояния »/
return! inportb(0x3?5));
}
/titttttttttttttttttttttttttttttttttttttttttttttttttttt/
It Функция охщами установки бита 7 регистра статуса */
/tttttttttttttttttttttttttttttttttttttttttttttttttttttt/
unsigned char wait bit7()
( while!(inportb(0x3F4) 4 0x80) -- 0); )
2.4. ПРИНТЕРЫ
В настоящее время разработано много различных
моделей принтеров, предназначенных для использования в
составе ПЭВМ. Популярными являются принтеры семей-
ства EPSON (серия FX). Они обеспечивают печать алфа-
витно-цифровой и графической информации, могут форми-
ровать любые наборы символов, так как имеют програм-
мно-загружаемый знакогенератор.
Принтеры используют режим точечной графики, что
позволяет печатать символы различной конфигурации,
чертежи, рисунки и т. п. Печатающая головка имеет де-
вять вертикально расположенных штырьков, приводимых
в действие электрическими сигналами. Наличие сигнала
вызывает удар штырька на бумагу через красящую
ленту. В результате отображается точка. Если одновремен-
но возбудить все штырьки, будет напечатана верти-
кальная линия. При перемещении головки в горизон-
тальном направлении можно напечатать различные изо-
бражения в полосе, состоящей из 9 точек по вертикали и
п точек по горизонтали (значение п определяется моделью
принтера). Ширина бумаги для принтера FX-800—254 мм,
FX-1000—406 мм. Плотность печати в вертикальном
направлении составляет 72 точки на дюйм, а в горизон-
78
тальком направлении может быть различной: 60, 120 и
240 точек на дюйм (напомним, что 1 дюйм равен 25,4 мм).
Принтер имеет встроенный знакогенератор, позволяю-
щий печатать символ, состоящий из точек, на основании
ASCII-кода, поступающего из системного блока. Расши-
ренные ASCII-коды могут использоваться для псевдогра-
фики и символов национальных алфавитов. Принтеры по-
зволяют изменять стиль шрифта и делать его более каче-
ственным, расширенным, уплотненным и т. п. Изменение
шрифта осуществляется с помощью кнопок на панели
управления либо по командам от системного блока. Для
некоторых команд используются управляющие ASCII-
коды с десятичными номерами от 0 до 31 и 127. Например:
13 — возврат каретки, 10 — перевод строки, 7 — звонок,
24 — отмена строки, 127 — забой знака. Однако для боль-
шинства из них формируются так называемые ESC-no-
следовательности, т. е. наборы байтов, первый из которых
имеет код ESC (десятичный номер 27). После ESC следует
байт с кодом команды, которым может быть любой символ
ASCII-кода. Затем идут байты с параметрами команды
(если они необходимы), например интервал между стро-
ками. Так, следующая функция вывода языка СИ устанав-
ливает интервал в т/216 дюйма:
fprintf (stdprn, "%с%с%с”, 27, 51, т); 1
Здесь 27 — код ESC; 51 — код команды (ASCII-код циф-
ры 3). Указанную функцию вывода можно записать и в
другом виде, например, так:
fprintf (stdprn, ”\033%с%с”, 51, m);
ИЛИ
fprintf (stdprn, ”0333%с", m);
Здесь 033в= 27.
С помощью ESC-последовательностей можно устанав-
ливать большое число различных шрифтов, задавать гра-
фический режим, определять любые собственные знаки,
выравнивать текст на странице, устанавливать интервал
между строками и символами, производить табуляцию,
выбирать различные наборы знаков для расширенной
таблицы ASCII-кода и т. п. Можно строить графические
изображения в режиме псевдографики, а также управлять
печатью каждой точки. Допускается исключение интерва-
ла между строками, что позволяет отображать большие
сложные рисунки. Перечень команд принтера FX-
800/1000 приведен в приложении.
79
Любые команды управления принтером могут быть вы-
ражены с помощью конструкций языков программиро-
вания, таких, как СИ, ПАСКАЛЬ и др. Скорость печати
зависит от модели принтера и для FX-85 составляет
160 знаков в секунду; для FX-800/1000— до 240 знаков
в секунду. Обеспечена одно- и двунаправленная печать.
В последнем случае символы печатаются при перемещении
головки слева направо и справа налево. Для модели
FX-800/1000 знаки из стандартной таблицы, поддержи-
ваемой знакогенератором принтера, имеют высоту 3,1 мм.
Ширина одного знака от 1,05 до 2,1 мм. Стандартный
интервал между строками составляет 1 /6 дюйма. Макси-
мальное число знаков в строке до 160 у принтера FX-800
и 272 у FX-1000. Допускается изготовление нескольких
копий через копировальную бумагу.
Печатающие устройства серии FX используют парал-
лельный интерфейс для подключения к системному блоку, в
соответствии с которым информация передается побайтно.
Она содержит коды символов и управляющие последова-
тельности.
Операционная система MS-DOS может работать с не-
сколькими параллельными устройствами. Каждое из них
имеет имя LPTn (п= 1, 2,...) и свой адаптер, управляе-
мый тремя регистрами: выходных данных, статуса и управ-
ления. Найти адреса портов этих регистров очень про-
сто. Предварительно нужно обратиться к началу обла-
сти переменных BIOS (см. табл. 1.3) и выбрать требуемый
параллельный канал, например LPT1. Тогда значение, про-
читанное по соответствующему адресу (в примере —
0:0408), даст номер порта выходных данных. Добавив к
этому значению единицу, получим номер порта статуса; ес-
ли добавить еще одну единицу, будет получен номер порта
управления.
Каждый посылаемый в принтер байт передается через
регистр выходных данных. Регистр статуса еообщает раз-
личную информацию о принтере (биты 2—0 не использу-
ются; бит 3:0 — ошибка принтера, 1 — отсутствие ошиб-
ки; бит 4:0 — принтер не связан с машиной, 1 — принтер
связан с машиной; бит 5:0 — бумага вставлена, 1 — нет
бумаги; бит 6: 0—подтверждение приема символа;
бит 7: 0— принтер занят, 1 — принтер свободен). В про-
цессе обмена для правильной передачи данных МП анали-
зирует его состояние. Регистр управления устанавливает
адаптер в исходное состояние и координирует вывод
данных (бит 0: кратковременное единичное значение
80
воспринимается как стробирующий сигнал для вывода
байта; бит 1: 1 — автоматический перевод строки после
возврата каретки; бит 2: 0 — инициализация порта прин-
тера; бит 3. 0 — отмена выбора принтера; бит 4. 0 — пре-
рывание принтера запрещено, 1 — прерывание принтера
разрешено; биты 5—7 не используются).
Перед началом работы необходимо восстанавливать в
принтере параметры печати по умолчанию (инициализи-
ровать принтер). Другими словами, должны быть отмене-
ны все специальные режимы, которые могла оставить
предшествующая программа. В языках высокого уровня
подобные действия выполняются автоматически. Для ини-
циализации необходимо в регистре управления сбросить
в нуль бит 2 примерно на 0,05 с. В этот момент в
единице должен быть только бит 3. После указанной за-
держки бит 2 устанавливается в единицу.
Перед обращением к принтеру необходимо проверить
его готовность. Для этого анализируется регистр статуса,
в котором могут быть такие коды: 5716 — принтер не го-
тов; 7716 — в принтере отсутствует бумага; F7i6 — принтер
выключен; DFi6 — принтер готов к работе. Ошибки могут
появиться и при печати. В этом случае их наличие тоже
отражается в регистре статуса: бит 3 содержит нуль, когда
произошла ошибка в принтере; в бите 4 — нуль, когда
принтер не связан с машиной; в бите 5 будет единица, если
кончилась бумага.
При работе с принтером на низком уровне программа
постоянно обращается к биту 7 регистра статуса, чтобы
узнать, можно ли передавать очередной байт. Сначала
этот байт записывается в регистр выходных данных, затем
на короткое время включается стробирующий импульс
(бит 0 регистра управления). После того как байт послан,
программа ожидает сигнала готовности принтера для пе-
редачи следующего байта. Подтверждающий сигнал выра-
жается не только в изменении бита 7: дополнительно
на некоторое время будет сброшен в нуль бит 6 регистра
статуса.
Если установить в единицу бит 4 управляющего ре-
гистра, то будет разрешено прерывание от принтера.
В этом случае сигнал подтверждения приема символа
(бит 6 регистра статуса) запускает на выполнение со-
ответствующую программу (см. § 1.5). Она вызывается
через вектор прерывания Fi6. Заметим, что подобные дей-
ствия могут быть реализованы не на всех ПЭВМ. В фоно-
вом режиме можно также использовать прерывания от
81
таймера, вырабатываемые через такие промежутки време-
ни, за которые принтер с гарантией отпечатает либо
примет в свой буфер один символ.
Рассмотрим два примера работы с принтером на низком уровне.
Первая программа написана на языках СИ и ассемблера. Она
позволяет выводить на принтер строку символов, введенную с клавиа-
туры. Ввод осуществляется на СИ, а вывод—на языке ассемблера, в
котором не используются обращения к процедурам обработки преры-
ваний. Адрес порта определяется после обращения к соответствующей
переменной BIOS:
(include <stdio.h>
(include (alloc.h>
extern int вуази20(unsigned char*);
void »ain()
I unsigned char *str;
str = lalloc(lOO); /» unieieuue namri in строка */
puts(‘\n!uejure строку, загаачшвцуки ciuuoiou Г);
gets!str); /* ввод строки */
вуаз®20(str); /» вывод строка на нраптер и прог-
раиие на языке ассеибдера »/
fprintf(stdprn,"\n"); /» передача ia принтер ciuuoiou
возврата каретки i перевода строки »/ }
.MODEL SHALL ; обшхение малой модели
.CODE ; сегмент кода
PUBLIC jsyasnZO ; ayasa20, доступная нз другого языка
jsyasaZO PROC near ; начадо программы
push bp ; значение Ьр помечается в стек
aov bp,sp ; в Ьр передается значение sp
bov bx, [bp+4] ; в Ьх передается адрес строки
Pop bp ; восстанавливается значение Ьр
sub ax,ax ; в ах заносится значение нудь
aov es.ax ; в es заносится значение нудь
aov dx.es:[408И] ; в dx номер порта выходного регистра
b: aov al,[bx] ; в al передается очередной снмвох
cap al,; если символ $, то переход иа метку
je rt ; rt ддя завериення программы
out dx.al символ в al пересылается в порт
inc dx ; к dx двахды прибавляется 1 и теперь
inc dx в dx номер порта регистра управления
aov al.ODH ; в al код ддя стробнрупцего импульса
out dx,al ; выдача в порт стробнрупцего импульса
aov al.OCS ; в al код ддя отмены строба
out dx.al ; отмена стробнрупцего импульса
dec dx в dx номер порта регистра статуса
no: in al,dx ; чтение состояния регистра статуса
,ЖЖ**************************Ж***********t**t***t»*»**♦**;
, Здесь следует проверить бит 3, н если он снгнаднзнрует ;
, о наднчнн оянбкн, то перейти к ее обработке ;
test al,308 ; ожидание готовности принтера (анадиз
jz по ; бита 7 в регистре статуса)
inc bx ; выбор сдедупдего снмвода в строке
dec dx ; в dx номер порта выходного регистра
jap Ь ; переход ддя вывода сдедупцего снмвода
rt: ret , возврат в программу на языке CR
82
_»yas«20 endp ; конец программы
EHD
В некоторых принтерах символы не печатаются до тех пор, пока не
будет получен код возврата каретки, завершающий строку, или пока не
будет передана полная строка, В связи с этим в конце программы на
СИ добавлено обращение к функции fprintf.
Вторая программа, написанная на языке ассемблера, анализирует
регистр статуса и позволяет установить наличие либо отсутствие бу-
маги в принтере:
.MODEL SHALL ; o6uiie»ae «aioi noieia
.DATA ; cement даннпх
txt.err DB 'В пранкере отсутствует 6уиага$'
txt_ok DB ’Бумага завравхенаГ
.STACK 10П ; сегмент стека
.CODE ; cement хода
include dos. inc ; вхичеппе макросредств
prin PROC ; пачахо нрограамв
aov ax,ODATA ; ds yctanasxneaetcj на
aov ds,ax ; сегмент даннвх
sub ax,ax ; a ax заноептеа значепие нуль
aov ез,ах ; в ез заносятся значение нуль
от dx.es:[408В] ; в dx заносится смеценне 408П, где
; храннтсу номер порта выходного регистра LFT1
inc dx ; теперь в dx хранится иомер порта статуса
io al.dx ; читается значение аз регистра статуса
test al,20В ; если в 5-и бите 0, го бумага npneytet-
je ok ; нует а выдается сообцение txt.ok
ov ah,9 ; 9 - функция вывода строки
ov dx,offset txt.err ; смеценае для выводимой строки
int 210 ; обраценне а прерыванию 210
SExit ; выход из программы
ок: нот ah,9 ; эти три строки подобны нредыдуцнм
вот dx,offset txt.ok ; сведения о лрервва-
int 21В ; няя 210 даны в паве 12
prin endp ; конец ярогргммы
SExit ; выход пз программа
EHD
2.5. ВВОД И ВЫВОД
ЧЕРЕЗ ПОСЛЕДОВАТЕЛЬНЫЙ КАНАЛ
Последовательный канал наиболее часто используют в
режиме асинхронной связи. Обмен между сопряженными
объектами осуществляется небольшими порциями длиной
до одного байта (см. рис. 1.4, б). Информация передается
и принимается побитово. Временные интервалы между
порциями (будем условно называть их байтами) не важны,
однако интервалы между битами имеют значение. В исход-
ном состоянии сигнал в линии имеет высокий уровень.
С началом передачи он сбрасывается в нуль, обозначая
стартовый бит. Далее идут биты данных в виде последова-
тельности высоких и низких уровней. За конечным из них
83
может следовать бит четности и далее один или два
стоп-бита (см. рис. 1.4). Стоп-биты задают минимальное
время ожидания следующего стартового бита. Для со-
гласованной работы в приемнике и источнике данных
должны быть установлены одни и те же параметры
обмена.
Связь по последовательному каналу в ПЭВМ семейства
IBM PC осуществляется с помощью микросхемы 8250
фирмы Intel. Базовые адреса ее портов хранятся в начале
области переменных BIOS (см. табл. 1.3). Каждое после-
довательное устройство имеет имя СОМп, где п — номер
канала. Практически на всех ПЭВМ рассматриваемого
класса СОМ1 имеет базовый адрес 3F8tе, а COM2 — 2F816.
Адаптер 8250 содержит восьмиразрядные программи-
руемые регистры со следующими адресами:
1) 3F8iе(2F81 е) — при работе на запись является ре-
гистром выходного слова для передачи, при работе на чте-
ние — регистром последнего входного слова для приема
(в обоих случаях эти функции выполняются, если бит 7 в
регистре управления обменом содержит нуль);
2) 3F8i6(2F8ie), 3F9i6(2F9ie) —регистры установки
скорости обмена, причем первый из них содержит млад-
ший байт, а второй — старший (эти функции выполняют-
ся, если бит 7 регистра управления обменом содержит
единицу);
3) 3F9i6(2F9ie) — регистр разрешения прерывания,
работающий только на запись (эта функция выполняется,
если бит 7 регистра управления содержит нуль);
4) 3FAi6(2FAie) — регистр определения типа преры-
вания;
5) 3FBi6(2FBi6) — регистр управления обменом;
6) 3FCie(2FCi6) —регистр управления модемом, ра-
ботающий только на запись;
7) 3FDi6(2EDi6) — регистр статуса обмена, работаю-
щий только на чтение; i,
8) 3FE)6(2FEie) — регистр статуса модема, работаю-
щий только на чтение.
Базовый адрес порта (см. п. 1) задается в соответ-
ствующей переменной BIOS (см. табл. 1.3). Адрес любого
другого регистра может быть вычислен путем добавления
нужного смещения.
Необходимые параметры последовательного порта
устанавливаются при его инициализации. Для этого нуж-
но:
1) задать скорость обмена информацией, которая
84
определяется такими числами: НО с 1 — 1040 (410i6),
150 с 1 — 768 (300,6), 300 с”1 — 384 (18016), 600 с^' —
192 (С01б), 1200 с“‘— 96 (6016), 2400 с1 —48
(3016), 4800 с'1—24 (1816), 9600 с1 — 12 (Ci6). Стар-
ший байт числа посылается в порт 3F9i6 (2F9ie), а млад-
ший—-в порт 3F816 (2F8i6). При этом бит 7 регистра
3FB16 (2FBi6) должен быть в единице;
2) установить биты регистра управления обменом —
3FB16 (2FB16), которые задают длину передаваемой пор-
ции информации (биты 1—0: 00—5 бит, 01—6 бит, 10—7
бит, 11 —8 бит), число стоп-битов (бит 2:0—1, 1 —2), спо-
соб контроля данных (биты 4—3: Х0 — отсутствие про-
верки и X — любое значение, 01 —на нечетность, 11 —
на четность), способ контроля четности (бит 5:1 — всегда
назначает биту четности значение 0, если биты 3 и 4 в еди-
нице, или 1, если бит 3 в единице, а бит 4 в нуле), установку
перерыва путем вывода строки нулей в качестве сигнала
от источника (бит 6: 1 — установка, 0 — сброс), измене-
ние адресов портов других регистров (бит 7, о котором
уже говорилось выше). Биты 5, 6 этого регистра обычно
сброшены в нуль;
3) если прерывания не используются, регистр разреше-
ния 3F916 (2F916) должен быть сброшен в нуль, при этом
в регистр определения типа прерывания 3FAi6 (2FAi6)
можно ничего не записывать. Если прерывания применя-
ются, допускается четыре их типа: 00 — изменение в ре-
гистре статуса модема; 01 — регистр выходного слова для
передачи свободен; 10 — получены данные в регистр вход-
ного слова для приема; 11—поступило условие перерыва
либо возникла ошибка приема. Перечисленные значения
записываются в биты 2—1 регистра определения типа пре-
рывания 3FA|6 (2FA16) • Бит 0 этого регистра устанавлива-
ется в единицу при наличии прерывания, а остальные
биты не используются. Для выбора требуемого преры-
вания необходимо задать определенные значения в регистр
3F916 (2F9ie): единицу в бит 0 для активизации прерыва-
ния при приеме данных, единицу в бит 1 для вызова пре-
рывания, когда регистр для передачи выходного слова
свободен, единицу в бит 2 для активизации прерывания
при ошибке приема данных и единицу в бит 3 для вызова
прерывания при изменениях в регистре статуса модема.
Остальные биты этого регистра не используются. Когда
активизируется одна из указанных ситуаций, возникает
аппаратное прерывание (сигнал на входах IRQ3 или IRQ4
микросхемы 8259, рассмотренной в § 1.5). Далее управле-
85
ние передается соответствующей программе обработки
прерывания (векторы Bte или С1б);
4) задать начальные параметны регистров модема,
который вырабатывает акустический сигнал для его после-
дующей передачи по телефонному каналу.
В процессе работы с адаптером необходимо постоянно
анализировать состояние регистра статуса 3FD16 (2FDie).
Если в его разрядах записаны единицы, то это означает:
бит 0 — получены данные, бит 1 — полученные данные
перезаписаны (предыдущая порция вовремя не считана),
бит 2 — ошибка при контроле на четность, бит 3 — ошибка
из-за нарушения синхронизации, бит 4 — получен сигнал,
указывающий, что другой объект запрашивает конец пере-
дачи, бит 5 — регистр выходного слова для передачи сво-
боден, бит 6 — регистр сдвига данных для передачи пуст
(он получает данные от регистра выходного слова и пре-
образует их в последовательный код), бит 7 — объект
не связан с машиной.
Конкретный последовательный порт СОМп можно за-
давать в программе путем указания номера канала п. Кро-
ме того, можно поменять значения для портов в соответ-
ствующих переменных BIOS (см. табл. 1.3). Допускается
присоединение выхода микросхемы 8250 к ее входу для
имитации обмена и проверки правильности работы аппа-
ратуры.
Охарактеризуем режимы работы последовательного
канала на передачу, прием и по прерываниям. Наиболее
простой — режим передачи, поскольку здесь отсутствует
необходимость выдерживания временных соотношений.
В описываемых ниже процедурах предполагается, что
адаптер уже инициализирован. Тогда программа передачи
данных в коммуникационный адаптер должна выполнять
следующие действия:
1) получить из порта 3FDi6(2FDi6) байт статуса;
2) проверить байт статуса на наличие,, ошибок и,
если они обнаружены, перейти к соответствующей обра-
ботке (наличие ошибок отражается в битах 1, 2, 3, 4);
3) проверить бит 5 регистра статуса на возможность
передачи данных;
4) если данные могут быть переданы, перейти к соот-
ветствующей процедуре, в противном случае повторить
операции пп. 1—3;
Процедура передачи включает создание и запись дан-
ных в порт 3F8iе (2F81 в), например пересылку очередного
символа из буфера.
86
Программа может принимать данные после инициали-
зации порта и установления связи с объектом. При этом
она должна выполнить такие действия:
1) получить из порта 3FDi6(2FDie) байт статуса;
2) проверить байт статуса на наличие ошибок и, если
они обнаружены, перейти к соответствующей обработке
(наличие ошибок отражается в битах 1, 2, 3, 4);
3) проверить бит 0 регистра статуса на возможность
приема данных;
4) если данные могут быть приняты, перейти к соот-
ветствующей процедуре, в противном случае повторить
операции пп. 1—3.
Процедура приема включает чтение данных из порта
3F816 (2F816) и их обработку (например, запись очеред-
ного символа в буфер).
Режимы приема и передачи данных в значительной
степени взаимосвязаны. Принимающий объект может
посылать сигнал XOFF (ASCII-код 19) для временной
приостановки быстро поступающих данных (в случае, если
он не успевает их обрабатывать). Далее может быть
выработан сигнал XON (ASCII-код 17), указывающий
передающему объекту на возможность возобновления пе-
редачи данных.
Работа по прерываниям позволяет программе обра-
щать внимание на коммуникационный адаптер только
тогда, когда активизируется соответствующий режим
(прием, передача или обработка ошибок). Любые допу-
стимые типы прерываний могут быть разрешены одновре-
менно. Процедура обработки должна правильно реагиро-
вать на возникшую ситуацию путем анализа содержимого
регистра 3FA16 (2FAie). Различные прерывания имеют сле-
дующие приоритеты: 1) ошибка или перерыв (сброс
путем чтения содержимого регистра статуса обмена); 2)
получение данных (сброс путем чтения информации из
регистра входного слова); 3) свободен регистр выходного
слова (сброс путем записи данных в этот регистр); 4) изме-
нение статуса модема (сброс после чтения регистра ста-
туса модема).
Для определения вектора коммуникационного преры-
вания необходимо:
1) установить точку входа в программу обработ-
ки прерывания (для СОМ1 и IBM PC/XT в DS: DX за-
носится сегмент: смещение точки входа, в AL, АН пе-
редаются значения Bib, 25[6 и вызывается прерыва-
ние 211б);
87
2) установить нужные биты в регистре разрешения
прерываний (порт 3F9ie или 2F9ie).
Программа обработки коммуникационного прерывания
может включать:
1) буфер (возможно, циклический) для символов;
2) средства анализа состояния коммуникационного
адаптера (работа на передачу или прием);
3) средства приема и передачи данных;
4) средства проверки возникновения нескольких пре-
рываний по различным признакам.
В конце программы должен следовать код завершения
аппаратного прерывания (mov al, 20Н и out 20Н, al).
В заключение напомним, что любое аппаратное пре-
рывание при необходимости может быть маскировано
(см. § 1.5).
2.6. ГРАФОПОСТРОИТЕЛИ ПЭВМ
К ПЭВМ можно подключать различные периферийные
устройства, например широко применяемые в САПР
графопостроители. Для их присоединения обычно исполь-
зуется последовательный канал. Одна и та же величина
скорости передачи устанавливается программно в ПЭВМ
и с помощью микропереключателей в графопостроителе.
Рассмотрим принципы работы и программного управ-
ления графопостроителем на примере устройств серии
МР3000. Они имеют следующие характеристики: эффек-
тивная площадь рабочего поля — 404X285 мм при разме-
ре листа 420X297 мм; максимальная точность — не ниже
±0,3 %; число пишущих элементов—8 (обеспечена их
автоматическая смена); метод удержания бумаги — маг-
нитный или электростатический; объем буферной памя-
ти — 5 и 24 К байт (в зависимости от модели); интер-
фейс — RS-232-C или Centronics; коды символов —
ASCII; потребляемая мощность — не более 50ьВт; масса—
6,5 или 8,5 кг (в зависимости от модели). В составе серии
МР3000 рассматриваются модели MP3100, МР3200,
МР3300, МР3400 (производимые в Японии).
Для чертежных работ используется графический язык,
поддерживаемый графическим процессором графопостро-
ителя. С его помощью чертятся прямые и ломаные линии,
окружности, эллипсы, секторы круга, выполняются различ-
ные виды штриховок и т. п. Работа может вестись в пря-
моугольных и полярных координатах. Информационная
посылка от ПЭВМ, обеспечивающая выполнение заданной
88
команды, состоит из последовательности байтов. Первый
из них содержит ASCII-код символа, идентифицирующего
команду. Затем идут параметры, например координаты
точки, в которую перемещается пишущий элемент. Тер-
минатор (ASCII-код с десятичным номером 3) указывает
на окончание команды с переменным числом параметров.
Так, если задано: М2200, 1500, то символ М говорит о
необходимости перемещения пишущего элемента; 2200
и 1500—горизонтальная и вертикальная координаты
точки, в которую осуществляется перемещение. Шаг
перемещения может быть назначен либо 0,25, либо 0,1 мм.
Каждый символ в команде представлен соответствующим
байтом в ASCII-коде. Таким образом, общее число байтов
будет равно одиннадцати (первый — для символа М,
второй — для цифры 2 ит. д.).
Ниже описывается большинство команд графического
языка для графопостроителей серии МР3000.
1. Dxi, yi, ..., хп, у nt — проведение линии через точки
с координатами (xj, уt), .... (х„, уп). Здесь и далее t — тер-
минатор.
2. EAxi, Ayi, ..., Ахп, AyП1 — проведение линии в от-
носительных координатах от текущего положения пишу-
щего элемента через точки с относительными координа-
тами (Axi, Ayi), .... (Ах п, Ауп).
3. Мх, у,— перемещение поднятого пишущего эле-
мента в точку с абсолютными координатами (х, у).
4. ОАх, Ау, — перемещение поднятого пишущего эле-
мента в точку с относительными координатами (Ах, Ау).
5. Р — рисование символов, например РАаБЬСс (в ре-
зультате будут вычерчены символы АаВЬСс, начиная от
текущего положения пишущего элемента).
6. Nn — рисование специальных символов, выби-
раемых значением п (крестик, стрелка и т. п.). Значение п
можно менять от 0 до 15.
7. (P<p)Axi, Ayi, ..., <р>Ахп, Ay„t — определение
любых новых символов. С помощью этой команды можно
построить генератор знаков русского алфавита. Ее код
в отличие от предыдущих двухсимвольный: (Р. Стан-
дартный размер поля для символа 14Х 21 относительных
единиц, при этом сам символ должен размещаться в поле
8X14. Наличие значения р не обязательно. Здесь и далее
такие символы будут заключаться в угловые скобки (( ) ).
Если р^99, пишущий элемент опускается; если pXJ
— 99, — поднимается. Диапазоны параметров: —98^Ах
5^98; —98^Ау^98; — 127 X Axi + ... + Ах„ X 127;
89
— 127 Ayi + ... + Ауп 127. Если Ах (Ау) —положи-
тельное число, перемещение осуществляется вправо
(вверх); если отрицательное,— влево (вниз). Относи-
тельными координатами узловых точек символа будут
(AxI; Ау,)... (АХп, Ауп).
8. Wxo, уо, г,, г2, <р,, ср2 <,d)t— вычерчивание окруж-
ности дуги или спирали, для которых: (х0, уо) — коорди-
наты центра; г,, г2 — начальный и конечный радиусы;
<р,, ф2 — начальный и конечный углы с шагом изменения
0,1°. Параметр d не обязателен. Если d> 1, соответ-
ствующая линия представляется ломаными отрезками.
Угол между линиями, исходящими из точки с координа-
тами (хо, уо), и концами каждого отрезка составляет
(d/10)°. Если d< 1, число таких отрезков равно d. Поло-
жительные углы <р, и ср2 отсчитываются от горизонтальной
оси, проведенной вправо от точки (хо, уо) против направ-
ления движения часовой стрелки. Диапазон изменения
углов от —32767 до 32767.
9. ]г,, г2, <р,, cp2<,d>t — вычерчивание окружности,
дуги или спирали, первая точка которых соответствует
текущей позиции пишущего элемента.
10. Ya, xi, у,, ..., хп, уп t — вычерчивание непрерывной
сглаженной линии через точки с абсолютными координа-
тами (хну,),..., (хп, у п). Так можно построить синусоиду,
змейку и т. п. Если а= 0, линия разомкнута; если а= 1,—
замкнута.
11. _а, Ах,, Ау,, ..., Ах п, Aynt — вычерчивание отно-
сительной непрерывной сглаженной линии.
12. а, хо, уо, Г|, г2, ср,, <р2, <рз — вычерчивание эллипса.
Если а=0, перемещение к начальной точке эллипса
осуществляется с поднятым пишущим элементом;
если а= 1,— с опущенным. Здесь (х0, уо) —коорди-
наты центра эллипса; г,, г2—длина большой и малой
осей; ср,, ср2— начальный и конечный углы; <рз — угол
между главной осью эллипса и горизонтальной ли-
нией системы координат. Все углы имеют шаг измене-
ния 0,1°.
13. Lp — спецификация типа линии (точечная, штри-
ховая, штрихпунктирная и т. п.). Тип линии и размер
штрихов задает параметр р (О^р^8);
14. Вр — спецификация штрихпунктирной линии с ша-
гом р.
15. Sn, <m,) —задание высоты (п) и ширины (т)
рисуемого символа. Параметр m является необяза-
тельным.
90
16. Qn, <m,) — смещение символа на п по вертикаль-
ной и m по горизонтальной оси.
17. Rep — поворот прямоугольных координат на угол ср
с шагом изменения 0,1°. Отсчет и диапазон изменения
значений углов такой же, как в п. 8.
18. 1р, — рисование символов под углом ср; р =
= 256tg (ср). Положительный угол отсчитывается от верти-
кальной линии, проведенной вверх от левого нижнего
угла симвбла в направлении движения часовой стрелки.
Здесь -4000<р<4000.
19. $н, (т,) — выбор типа стандартного шрифта
в соответствии со значениями пит.
' 20. А — установка параметров рисования символов,
первоначально заданных по умолчанию (они будут такими
же, как при включении графопостроителя).
21. Хр, q, г <, ti <, t2 » t — рисование координатных
осей, параллельных осям х и у. Если р = 0 или р= 2, вычер-
чивается вертикальная ось; если р= 1 или р=3,— гори-
зонтальная. При р=0 или р= 1 значение q определяет
расстояние между штрихами соответствующей оси. Если
р = 2 или р= 3, значение q задает длину оси. Параметр г
определяет число штрихов. Значения ti и U задают длину
штрихов в положительном и отрицательном направлениях.
22. %п, х, у, d, <pt — вычерчивание прямоугольника
и при необходимости его штриховка. Если n = 1, вычер-
чивание только прямоугольника; если п=2,— только
его штриховка; при п=3 вычерчивание и штриховка.
Здесь х и у — длины горизонтальной и вертикальной
сторон прямоугольника; d — расстояние между штрихами
(0 < d 4000), ср — угол, под которым осуществляется
штриховка. Отсчет и диапазон изменения углов такой же,
как в п. 8.
23. %п, ri, Г2, cpi, <р2, d, cp:!t — вычерчивание и штрихов-
ка секторов круга. Если п= 11, только вычерчивание
сектора; если п= 12, только его штриховка; при п= 13
вычерчивание и штриховка. Здесь п и щ — внутренний
и внешний радиусы сектора. Параметры cpi и ерз опреде-
ляются так же, как в п. 8, a d и ерз — как в п. 22.
24. %п, d, ср, Xi, yi, ..., хп, ynt — вычерчивание и штри-
ховка многоугольника. Если п= 21, только вычерчивание
многоугольника; если п=22, только его штриховка; при
п=23 вычерчивание и штриховка. Параметры х(, yi, ...,
х п, у п определяются так же, как в п. 1, a d и ср— как
в п. 22.
25. &р, q, г — сжатие (расширение) вычерчиваемой
91
фигуры. Здесь р/г и q/r — коэффициенты сжатия по гори-
зонтальной и вертикальной осям.
26. /х, у, <р, — поворот системы координат. Здесь
(х, у) — координаты центра вращения; ср — угол поворо-
та, который определяется так же, как в п. 8.
27. 'х, у, — перемещение системы координат. Здесь
(х, у) —точка нового начала системы координат.
28. >xi, yi, ..., хп, ynt — выделение области рабочего
поля графопостроителя с координатами (xi, yi), ...,
(х п, уп), в которой рисование запрещено.
29. : — установка графопостроителя в начальное со-
стояние.
30. Н — установка пишущего элемента в исходное
положение (левый нижний угол рабочего поля).
31. Jn, — выбор нового пишущего элемента с номером
п (0^п^8).
32. !р <, n > t — задание скорости v= 400р/10 мм/с
(О^р^Ю). Значения-.п задают номера пишущих эле-
ментов, для которых следует изменить скорость.
33. Тп — включение лампочки ALARM/PROMPT —
при n = 1 и ее выключение при п = 0 на панели управления
графопостроителя.
34. G — предписание необходимости передачи данных
от графопостроителя о текущих абсолютных координатах
пишущего элемента в ПЭВМ. Выходные данные от графо-
построителя представляются в виде: X, Y, Р, t. Здесь X
и Y — горизонтальная и вертикальная координаты, со-
держащие каждая по шесть цифр; Р — состояние пишу-
щего элемента, тоже содержит шесть цифр; t—терми-
натор. Если Р = 10, элемент 1 поднят; если Р = 11, — опу-
щен; при Р= 20 элемент 2 поднят, при Р= 21 —опущен
и т. п. Сначала ПЭВМ посылает на графопостроитель
команду G. В ответ на нее он возвращает в ПЭВМ ука-
занную выше последовательность.
35. =tit2 — использование для назначения термина-
тором символов возврата каретки и перевода строки
(десятичные номера 13 и 10). Символы ti, to либо оба
символа t, и t2 рассматриваются как терминатор.
36. С — подобна команде G, но координаты могут быть
введены в ПЭВМ в любой момент времени при движении
каретки. Для этого достаточно нажать кнопку ENTER
на панели управления.
37. Команды V, @ и 4Т позволяют определить состоя-
ние графопостроителя (режим паузы, свободный объем
буферной памяти, наличие или отсутствие ошибок и т. п.).
92
38. DPri, <pi, г п, ср nt — проведение линии через точки
с координатами (п, <pi), (гп, $,) в полярной системе.
Здесь углы cpi, срп определяются так же, как в п. 8;
Г1 ..., гп — расстояние от начала координат до соответ-
ствующих точек. Эта и последующие команды для работы
в полярной системе координат задаются двумя буквами
(здесь D и Р).
39. Команды ЕР, MP, ОР подобны ранее рассмотрен-
ным командам Е, М и О, за исключением того, что вместо
прямоугольных (х, у) используются полярные (г, ср) коор-
динаты.
Рассмотрим пример простой программы для вывода информации
на графопостроитель. Она написана на языке СИ; ее работоспособ-
ность проверена на ПЭВМ IBM PC/AT с графопостроителем МР3100,
который подключен к последовательному каналу с именем COM2. В ре-
зультате ее работы вычерчиваются линии и символы:
/ttttttttttttittitttttttttttttttttit/
/II ВЫЧЕРЧИВАНИЕ ЛИНИЙ И СИМВОЛОВ II/
/ttttttttttttttttttttttttttttttttttt/
Minclade <stdio.h>
void fflainl) /I установки паг 0,1 ин I/
I FILE tfopep(),tfp;
fp:fopen("co»2','*");
fprintfffp,"/• инициализации графо-
построитеи I/
fprintf(fp,"D1200,1\3*); /I начерчивание линии из
начала координат в точку (1200,1) I/
fprintf(fp,‘М200,300,*); /I переиецеиие в точку с
координатами (200,300) I/
fprintf(fp,“Е100.200\3“); /I вычерчивание линии из
точки (200,300) в точку (200+100,
300+200), т.е. о точку (300,500) I/
fprintf(fp,"0100,-200,"); /I переиецеиие и точку с
относительными координатами
(100,-200) I/
fprintf(fp,‘Pl 2 А В \3*);
/I вычерчивание сихвоюв 1 2 А В I/
fprintf(fp,'1150,01 2 А В \3“);
/» рисование сихвоюв под упои I/
fprintf(fp,"550,50,01 2 А В \3‘);
/I рнсованне сихвоюв под угш
с увеличенныин разиераии •/
fclose(fp);
)
2.7. УСТРОЙСТВА ДЛЯ СЪЕМА
ГРАФИЧЕСКОЙ ИНФОРМАЦИИ
Устройства для съема графической информации
(УСГИ) обычно подключаются к последовательному
каналу. Их основная функция состоит в съеме и передаче
в системный блок координат точек чертежа. Этот процесс
93
осуществляется путем установки на некоторый элемент
рисунка специального указателя и нажатия кнопки ВВОД.
Координаты могут сниматься либо в режиме ввода отдель-
ных точек, либо при перемещении указателя вдоль линии
чертежа через некоторые заданные интервалы времени.
Сначала в УСГИ посылается команда, предписывающая
выполнение тех или иных действий. В ответ на нее в ПЭВМ
возвращается последовательность байтов, содержащих
требуемую информацию.
Принципы работы и программного управления УСГИ
рассмотрим на примере устройств типа KD3200, KD3300,
KD4300, KD4600, KD3800 (производятся в Японии). Они
имеют следующие характеристики: метод съема — индук-
ционный с получением абсолютных координат; эффектив-
ная площадь рабочего поля для перечисленных выше мо-
делей соответственно 297X210, 305X305, 380X260, 460Х
Х310, 381X381 мм; точность съема — ±0,5 мм; разре-
шающая способность — 0,1 мм; максимальная скорость
съема — до 60 точек в секунду; потребляемая мощность —
не более 6 Вт; масса — от 3,2 до 4,8 кг (в зависимости от
модели).
Съем информации осуществляется с помощью курсора
(рис. 2.5, а), либо пера (рис. 2.5, б), позволяющих выбрать
точку, данные о координатах которой следует ввести в
Рис. 2.5. Устройства для съема информации
ПЭВМ. На эту точку необходимо установить либо центр
перекрестия курсора, либо наконечник пера. Ввод инфор-
мации (т. е. съем координат и передача их в ПЭВМ) осу-
ществляется при нажатии любой кнопки (этому должен
предшествовать запрос соответствующих данных со сто-
роны ПЭВМ). Однако каждая кнопка (Z, 1, 2, 3) выдает
в системный блок свой собственный код, что позволяет
задавать дополнительные действия, например перемеще-
ние в новую точку, изменение цвета отображаемых данных
94
на экране дисплея и т. п. Курсор и перо нельзя исполь-
зовать одновременно. Как и в графопостроителе, началом
координат является левый нижний угол.
Передача данных от УСГИ может осуществляться в
двух форматах: ASCII и двоичном. Здесь мы рассмотрим
только первый из них (рис. 2.6). Общая информационная
КООРДИНАТЫ ТОЧКИ
ПО ГОРИЗОНТАЛЬНОЙ
оси
БАЙТЫ С ЗАПЯТЫМИ
(ШЕСТНАДЦАТЕРИЧНЫЙ
КОД 2С)
Рис. 2.6. Иллюстрация принципов взаимодействия
ПЭВМ и* УСГИ
посылка содержит 12 байт. Первые четыре байта дают
координаты точки по горизонтальной оси (каждый байт —
одна цифра от 0 до 9 в ASCII-коде). Если значение коорди-
наты имеет меньше четырех значащих десятичных цифр,
недостающие цифры заменяются нулями в ASCII-коде
(передача данных в ПЭВМ осуществляется, начиная со
старших разрядов числа). Пятый байт содержит ASCII-
код запятой. Затем идут четыре байта со значением коор-
динаты точки по вертикальной оси. Десятый байт также
содержит ASCII-код запятой. Далее идет байт, отобра-
жающий состояние кнопок курсора или пера. В нем будет
записан ASCII-код цифр 1,2, 4 или 8 в зависимости от того,
какая кнопка нажата (Z, 1, 2 или 3). Последний байт
содержит терминатор, которому соответствует ASCII-код
с номером 10 (перевод строки). Установкой микропере-
ключателей УСГИ можно сдел ать так, чтобы вместо одного
байта выдавались два: возврат каретки (13) и перевод
строки (10). Существует еще один ASCII-формат, когда
перед горизонтальной и вертикальной координатами вы-
дается знак (плюс или минус): ±ХХХХ, ±YYYY, F CR
LF (CR — возврат каретки — Carriage Return; LF —
перевод строки— Line Feed).
95
Рассмотрим команды для управления УСГИ.
1. Т— команда для тестовой проверки. Сначала на
УСГИ посылается ASCII-код буквы Т (т. е. 54i6) • Если
затем передать код любого символа, то УСГИ принимает
его и сразу же возвращает назад в ПЭВМ.
2. U — включает лампу STATUS на панели УСГИ.
3. V — выключает лампу STATUS на панели УСГИ.
4. Z — включает звуковой сигнал в УСГИ приблизи-
тельно 40 мс.
5. S — приостанавливает передачу данных от УСГИ.
Используется либо при передаче данных от УСГИ непре-
рывным потоком (для завершения этого процесса), либо в
режиме съема точек, для того чтобы предотвратить ввод
данных в случае ошибочного нажатия кнопки.
6. Р — задает режим ввода точек. Сначала от ПЭВМ в
УСГИ передается ASCII-код буквы Р (т. е. 501б). В ответ
на это после установки курсора или пера на эффективное
рабочее поле и нажатия любой кнопки УСГИ возвращает
в ПЭВМ информационную посылку из 12 байт, показан-
ную на рис. 2.6.
7. Y — задает режим ввода точек. Сначала от ПЭВМ в
УСГИ передается ASCII-код буквы Y (т. е. 59(е) • В ответ
на это УСГИ возвращает в ПЭВМ информационную по-
сылку из 12 байт (см. рис. 2.6). Здесь не надо нажимать
кнопки. Если курсор или перо находится вне эффективного
рабочего поля, для горизонтальной и вертикальной коор-
динат возвращаются значения 9999. При ненажатых
кнопках курсора или пера в байте F содержится ASCII-код
цифры 0.
8. Один из символов Н, I, J, К, L, М, N, О задает режим
потока данных. В этом случае УСГИ начинает выдавать
данные непрерывно. Их формат соответствует показан-
ному на рис. 2.6,. Каждый символ задает различную ско-
рость выдачи информации от УСГИ в ПЭВМ. В режиме Н
посылаются две информационные посылки"йз 12 байт (см.
рис. 2.6) в секунду, в режиме I—четыре, J — десять,
К — двадцать, L — сорок, М, N и О — шестьдесят (при
скорости передачи данных по последовательному каналу
9600 с'1).
9. Один из символов А, В, С, D, Е, F, G задает режим
включаемого потока данных. Для него в отличие от пре-
дыдущего случая информация от УСГИ будет поступать
только при нажатии какой-либо кнопки курсора или пера.
Различные символы задают различные скорости съема дан-
ных: @ —две информационные посылки в секунду, А —
96
четыре, В — десять, С — двадцать, D — сорок, Е, F и G —
шестьдесят при скорости передачи данных по каналу
9600 с-'.
10. а—установка режима относительных координат.
После передачи от ПЭВМ в УСГИ ASCII-код буквы а
(т. е. 611б) команды Р, Y, а также команды потока будут
вызывать передачу от УСГИ к ПЭВМ данных в относи-
тельных координатах. Для каждой новой точки они будут
отсчитываться по отношению к предыдущей. Если новая
точка расположена правее или выше старой, ее координа-
ты будут положительными; если левее или ниже,— отрица-
тельными.
1 1. b — переводит УСГИ из предыдущего режима в ре-
жим абсолютных координат.
12. сХ, Y CR LF—установка нового начала коорди-
нат, смещенного вправо от левого нижнего угла эффектив-
ного рабочего поля на значение X и вверх на значение Y.
Здесь с — символ команды (его ASCII-код — 63iе); CR и
LF — байты возврата каретки и перевода строки; X и Y —
десятичные числа. Снимаемые координаты могут иметь
положительные и отрицательные значения в зависимости
от того, в какой области они находятся. Горизонтальные
координаты отрицательны, если точка находится левее
оси Y, а вертикальные — если она расположена ниже
оси X.
13. d — исключает предыдущий режим и устанавли-
вает первоначальную систему координат.
14. Wn — устанавливает режим инкремента, в котором
координаты для пп. 8, 9 будут выдаваться в ПЭВМ только
через п единиц по горизонтальной или вертикальной оси
(если п= 10, то при разрешении 0,1 мм—через 1 мм).
15. R — исключает команду Wn (того же эффекта мож-
но достигнуть, используя W0).
16. е Хо, Yo, Xi, Yi CR LF — поворачивает систему
координат на угол ср, который задается наклоном прямой,
проведенной через точки (Хо, Yo) и (Xi, Y,) относительно
горизонтальной оси (0° < ср < 90°). Новые координатные
оси будут повернуты против направления движения часо-
вой стрелки на угол ср относительно старых осей.
17. f — исключает команду из п. 16.
4 Скляров В. А.
97
2.8. МАНИПУЛЯТОРЫ
Среди других устройств, часто подключаемых к ПЭВМ,
следует охарактеризовать манипуляторы типа «мышь»,
джойстик и световое перо. Манипулятор типа «мышь»
представляет собой небольшую коробочку, которую можно
двигать по плоской поверхности. Перемещение манипу-
лятора вызывает аналогичные перемещения курсора на
экране дисплея. Такой способ очень удобен при работе с
различными картинками, таблицами, графиками и т. п.
Джойстик — это рукоятка, посредством которой можно
управлять движением курсора на экране дисплея. Джой-
стик и «мышь» содержат одну либо несколько кнопок,
используемых для фиксации местоположения курсора
или для ввода команд.
Доступ к джойстику осуществляется через игровой
аналоговый порт с адресом 20116, который поддерживает
два устройства и позволяет получать две координаты и
состояния двух кнопок (бит 0 — координата X первого
джойстика, бит 1 — координата Y первого джойстика,
биты 2, 3 — аналогичные координаты для второго джой-
стика, биты 4, 5 — состояния кнопок 1 и 2 первого джой-
стика, биты 6, 7 — состояния кнопок 1 и 2 для второго
джойстика). Если послать в этот порт любой байт, то биты
3—0 будут сброшены в нуль. Далее необходимо считы-
вать значения требуемого бита с подсчетом временного ин-
тервала. Как только выбранный бит установится в еди-
ницу, вычисленный интервал будет пропорционален пози-
ции джойстика по соответствующей оси.
Световое перо представляет собой устройство опреде-
ленной формы (похожее на авторучку) со встроенным
фоточувствительным элементом. Когда оно поднесено к
экрану, световой поток, образуемый светящейся точкой на
поверхности экрана, поступает к фоточувствительному
элементу. Совместная система синхронизации позволяет
отслеживать местоположение светового пера на экране, и
тем самым с его помощью можно считывать координаты
фигур, получать различные изображения и т. п. Соответст-
вующие аппаратные средства входят в состав видеосисте-
мы. Данные о позиции светового пера хранятся в блоке
CRTC (см. § 2.2).
Все перечисленные устройства требуют специальной
программной поддержки. Для этого с помощью средств
ОС подключаются программы-драйверы, осуществляющие
обслуживание соответствующих манипуляторов.
3. ОПЕРАЦИОННАЯ СИСТЕМА MS-DOS
3.1. ОБЩИЕ СВЕДЕНИЯ
ОБ ОПЕРАЦИОННБ1Х СИСТЕМАХ
ОС является одним из главных компонентов общего
программного обеспечения ПЭВМ. Она позволяет отде-
лить программы пользователя от непосредственного взаи-
модействия с аппаратурой. На ПЭВМ наиболее распрост-
ранены ОС типа MS-DOS, OS/2, СР/М и UNIX. Из них
наибольшую популярность получила MS-DOS. Опера-
ционная система OS/2 ориентирована на ПЭВМ семейства
PS/2, отечественные аналоги которой отсутствуют. ОС
MS-DOS широко используется на ПЭВМ семейств IBM
PC/XT, АТ, PS/2 и др.
ОС обеспечивает выполнение двух главных задач [4]:
1) поддержку работы всех программ и обеспечение их
взаимодействия с аппаратурой;
2) предоставление пользователям возможностей обще-
го управления машиной.
В рамках первой задачи обеспечиваются взаимодейст-
вие программ, работа с внешними устройствами, динами-
ческое распределение оперативной памяти, выявление
сбойных и ошибочных ситуаций, получение информации о
состоянии оборудования, его настройка и т. п. Общее
управление машиной осуществляется с помощью команд
ОС, посредством которых можно выполнять такие дейст-
вия, как форматирование дисков, копирование и удаление
файлов, чтение каталогов и т. п.
ОС для ПЭВМ содержит следующие основные компо-
ненты: файловую систему; драйверы периферийных уст-
ройств; процессор командного языка.
Файловая система включает развитые возможности
работы с файлами. Файл — это последовательность запи-
сей, размещаемых на внешних запоминающих устройст-
вах и рассматриваемых в процессе пересылки и обра-
ботки как единое целое. Каждый файл имеет уникальное
99
имя, зарегистрированное в каталоге, или директории.
Каталог может иметь собственное имя и храниться в
другом каталоге. Таким образом строятся иерархические
файловые структуры.
Одна из важнейших функций ОС — поддержка работы
широкого набора периферийных устройств. В их число
входят как стандартные компоненты ПЭВМ (клавиатура,
дисплей, накопители на жестких и гибких магнитных
дисках, принтер), так и дополнительные устройства,
специализирующие ПЭВМ на заданное применение (мани-
пуляторы, графопостроители, устройства съема координат
ит. п.). Для управления периферийным оборудованием в
составе ОС используются специальные программы, назы-
ваемые драйверами. Драйверы стандартных компонентов
входят в состав ОС, а для специальных устройств могут
подключаться при запуске машины.
Для взаимодействия пользователя с ПЭВМ в ОС
вводится командный язык, на основе которого строятся
указания на выполнение тех или иных действий (копиро-
вание файлов, запуск программ и т. п.). Анализ и выпол-
нение таких указаний пользователя производятся команд-
ным процессором ОС.
В последующих главах пособия рассматривается ОС
MS-DOS версии 3.30. Для ее работы требуется примерно
60 К байт оперативной памяти.
3.2. СТРУКТУРА MS-DOS
Важнейшей отличительной особенностью ОС является
модульность. Это свойство позволяет изолировать друг от
друга отдельные части сложной системы, облегчая ее раз-
работку и эксплуатацию. В состав MS-DOS входят сле-
дующие основные модули: базовая система ввода-вывода
(BIOS); блок начальной загрузки (Boot Record); модуль
расширения базовой системы ввода-вывЬ'да (файл
IBMBIO.COM); модуль обработки прерываний (файл
IBMDOS.COM); командный процессор (файл COM-
MAND.СОМ); утилиты ОС.
Базовая система ввода-вывода находится в ПЗУ сис-
темного блока; все остальные модули записаны на магнит-
ном диске. Блок начальной загрузки ОС, или «загрузчик»,
всегда записан в первом секторе системного диска. Модули
IBMBIO.COM и IBMDOS.COM хранятся в двух специаль-
ных скрытых файлах на системном диске, места размеще-
ния которых зафиксированы и известны загрузчику. /Со-
100
мандный процессор — это файл, который может занимать
любое место на системном диске. Утилиты ОС — систем-
ные программы, которые могут находиться в любых фай-
лах на любых дисках.
BIOS в ПЗУ занимает 8 К байт, начиная с сегмент-
ного адреса FEOO|6. Фактически эта программа является
частью машины, поэтому она должна быть компонентом
любой ОС, поставляемой для ПЭВМ семейства IBM/PC.
BIOS реализует следующие основные функции:
1) автоматическую проверку аппаратных компонентов
при включении ПЭВМ;
2) вызов блока начальной загрузки ОС (загрузка в
память программ ОС происходит в два этапа: сначала —
блока начальной загрузки с передачей на него управления;
затем с его помощью — остальных модулей ОС);
3) обслуживание системных вызовов или прерываний
нижнего уровня (векторы от 0 до IFie) •
Блок начальной загрузки — это небольшая программа
(ее длина всего 512 байт), основная функция которой
заключается в считывании с дисков в оперативную па-
мять двух других частей ОС— модуля расширения ба-
зовой системы ввода-вывода и модуля обработки прерыва-
ний. При запуске ПЭВМ либо после включения напряже-
ния питания, либо путем нажатия клавиш УПР — ДОП —
УДЛ (Ctrl—Alt — Del) осуществляется считывание пер-
вого сектора с дискеты, установленной в дисковод А, и
размещение его в оперативной памяти по адресу 31744
(7С001б). Затем BIOS передает управление по этому
адресу, и последующие действия выполняет программа-
загрузчик. Если дискета не установлена в дисковод А,
соответствующее считывание выполняется с жесткого
диска.
В начале «загрузчика» находятся служебная информа-
ция и блок параметров (BIOS Parameter Block — ВРВ).
Здесь содержатся такие данные (в скобках указан размер
соответствующего поля):
1) переход типа near на программу загрузки — jmp
адрес (3 байта);
2) имя фирмы-производителя и версия системы (8
байт);
3) число байтов на сектор (2 байта). Здесь начинается
блок параметров BIOS;
4) число секторов в кластере (1 байт);
5) число резервных секторов перед первой таблицей
101
размещения файлов (FAT) —File Allocation Table (2 бай-
та) ;
6) число таблиц размещения файлов (1 байт);
7) максимально возможное число 32-байтных элемен-
тов корневого директория (2 байта);
8) общее число секторов на диске (2 байта);
9) формат (см. табл. 2.4) диска (1 байт);
10) число секторов в одной таблице размещения фай-
лов (2 байта);
11) число секторов на дорожке или цилиндре (2 байта);
12) число головок записи/чтения (2 байта);
13) число скрытых секторов (2 байта).
Далее идет собственно программа-загрузчик.
Расширение средств BIOS с помощью дополнительного
модуля придает гибкость ОС, позволяя управлять с ее по-
мощью таким набором аппаратных средств; который наи-
более точно соответствовал бы замыслу разработчиков.
При этом появляется возможность включения дополни-
тельных программ, обслуживающих новые внешние
устройства (драйверов). В целом модуль IBMBIO.COM
решает три основные задачи:
1) настройку на нужды конкретной ОС;
2) исправление любых ошибок BIOS в ПЗУ (если
возникает такая необходимость) путем изменения векто-
ров прерываний так, чтобы управление при обращении к
операциям BIOS сначала попадало в IBMBIO.COM, а уже
затем — в BIOS;
3) обслуживание новых периферийных устройств, та-
ких, как жесткие диски большой емкости, графопострои-
тели и т. п.
Поскольку возможность подключения новых устройств
в ПЭВМ при наличии соответствующих средств поддержки
их работы имеет важное значение, процедура включения
обслуживающих программ сильно упрощена (в MS-
DOS — с версии 2.0). Когда управление впервые после за-
пуска ОС передается модулю IBMBIO.COM, он проверяет,
нет ли на системном диске файла конфигурации ОС
(CONFIG.SYS). Если этот файл найден, то считываются
его команды вида DEVICE = ..., которые указывают, какие
дополнительные драйверы необходимо загрузить. Каждый
новый драйвер рассматривается в оперативной памяти как
добавление к модулю IBMBIO.COM. Такой подход упро-
щает подключение новых устройств, повышает модуль-
ность ОС и не затрагивает ее системных файлов.
Модуль обработки прерываний образует верхний уро-
102
вень ОС, с которым взаимодействует большинство при-
кладных программ. Компонентами этого модуля являются
программы, обеспечивающие работу файловой системы,
устройств, обслуживание некоторых специальных ситуа-
ций, связанных с завершением программ, их искусствен-
ным прерыванием и обработкой ошибок. Различают слу-
жебные процедуры (программы обработки прерываний)
ОС, имеющие собственные векторы (начиная с 20i6) и
имеющие общий вектор с номером 33 (21ie). Первая груп-
па называется прерываниями ОС, а вторая — функциями
ОС.
Следующий модуль, размещаемый на системном ди-
ске,— командный процессор (файл COMMAND.COM).
При загрузке в оперативную память он разделяется на
резидентную часть, которая располагается вслед за двумя
рассмотренными модулями ОС, и полурезидентную, поме-
щаемую по старшим адресам. Существует еще одна,
третья, часть, которая используется только временно. При
запуске ОС она осуществляет поиск специального команд-
ного файла AUTOEXEC.BAT и, если он найден, выполняет
его. Далее эта часть COMMAND.COM уже не нужна.
Основные функции командного процессора заключают-
ся в приеме, анализе, выполнении указаний пользова-
теля и обработке командных файлов (файлы типа ВАТ).
Указания пользователя иначе называют командами ОС.
Они позволяют готовить диски для работы, копировать
файлы, переименовывать их, удалять из каталогов, сме-
нять текущий каталог и текущий накопитель, изменять
режим работы дисплея, выводить содержимое текстовых
файлов на экран дисплея, на принтер или в коммуника-
ционный канал и т. п. Важнейшая разновидность коман-
ды ОС — запуск любой прикладной программы. Ею может
быть и утилита ОС — программа, выполняющая какую-
либо сервисную системную функцию, например началь-
ную разметку диска.
Три возможных типа файлов обработки команд разли-
чаются расширениями их имен. Используются три расши-
рения, которые перечисляются ниже в порядке их приори-
тетности: СОМ — программный файл в одном формате;
EXE — программный файл в другом формате; ВАТ — ко-
мандный файл. Когда COMMAND.COM находит програм-
мный файл, он выполняет его загрузку, добавляет пре-
фикс программного сегмента и запускает на выполнение.
Интерпретатор команд и программы, выполняющие
внутренние (резидентные) команды ОС, содержатся в ча-
103
сти COMMAND. СОМ, помещаемой по старшим адресам
оперативной памяти. Эта полурезидентная часть может за-
тираться прикладными программами. При необходимости
использования интерпретатора команд резидентная часть
COMMAND.COM сначала проверяет, находится ли он в
памяти. Если он испорчен другими программами, то выпол-
няется соответствующая подзагрузка с текущего диска.
Если в процессе работы появится сообщение: «Insert
DOS disk...» (установите диск с ОС), то это означает, что
на текущем диске нет файла COMMAND.COM (а его необ-
ходимо загрузить).
С помощью файла COMMAND.COM можно осуществ-
лять частичную перезагрузку системы (без повторного
выполнения файлов IBMBIO.COM, IMBDOS.COM). Для
этого достаточно ввести команду COMMAND. Тогда
повторно загрузится только COMMAND.COM. Это позво-
лит обновить версию интерпретатора команд и выполнить
командный файл AUTOEXEC.BAT.
Последнюю часть ОС составляют утилиты. Их обра-
зуют системные программы, хранимые на дисках. Как и
другие программные файлы, они имеют расширение СОМ
или EXE. Их примерами являются FORMAT.COM,
DISKCOPY.COM и т. п.
3.3. ФАЙЛОВАЯ СИСТЕМА
MS-DOS поддерживает иерархическую структуру фай-
ловой системы, представляемую в виде дерева. Корень
дерева образует корневой каталог (Root Directory), каж-
дый элемент которого имеет размер 32 байта. Он располо-
жен на диске после загрузчика и ТРФ (основного экземп-
ляра и копии). Элемент корневого каталога ставится в
соответствие либо файлу, размещаемому на диске, либо
каталогу более низкого уровня — подкаталогу. Подката-
лог тоже состоит из таких же элементов (efo длина не
ограничена).
Иерархическую структуру файлов необходимо строить
так, чтобы подкаталоги ссылались на программы, имею-
щие общие свойства. Например, одну группу могут образо-
вать исходные тексты программ на одном алгоритмиче-
ском языке, текстовые файлы, объектные модули, файлы
типа СОМ и EXE и т. п.
Просмотреть содержимое корневого каталога можно с
помощью команды DIR, например:
A)DIR (ВВОД)
104
Здесь А) — формат приглашения ОС, задающий требуе-
мый диск А. Напомним, что подчеркиваются те символы,
которые набирает пользователь (для MS-DOS набираемые
буквы могут быть строчными или прописными). Команда
завершается нажатием клавиши ВВОД. Символ А, а так-
же другие возможные символы: В, С, D, ... являются
логическими именами физических дисковых накопителей.
Если текущим является диск А и необходимо просмотреть
корневой каталог диска В, вводится команда:
A)DIR В: (ВВОД)
Требуемый диск идентифицируется двумя символа-
ми — логическим именем и двоеточием. Переход к текуще-
му диску В осуществляется командой
А)В:(ВВОД)
После этого появится приглашение В). Аналогично осу-
ществляется переход к любому другому текущему диску.
Другие модификации команды DIR; А> PIR/p/RROn)
и А>ОП<Ау/вВОД> позволяют просматривать каталог
постранично (р) и по всей ширине экрана (w).
Выше уже говорилось, что в корневом каталоге могут
быть ссылки на файлы специального вида — подкаталоги.
Для работы с ними используются команды- MD, CD, RD.
Команда MD создает новый подкаталог с заданным име-
нем, например:
A) MD КАТ1 (ВВОД)
В результате будет создан подкаталог КАТ1, маршрут к
которому выражается записью: A:\KAT1. Для того чтобы
сделать этот подкаталог текущим, необходимо ввести ко-
манду
A) CD KATI (ВВОД)
Чтобы имя нового текущего подкаталога появилось в
приглашении, необходимо сразу после запуска ОС ввести
команду
A) PROMPT $p$g (ВВОД)
После этого на экране появится новое приглашение:
A:\KAT1). Указанную команду целесообразно поместить в
файл AUTOEXEC.BAT. Таким образом, команда CD обес-
печивает переход к новому текущему подкаталогу. Коман-
да PROMPT задает формат приглашения ОС (подробно
она будет рассмотрена далее, в § 3.4).
105
Команда RD служит для исключения подкаталога, из
которого ранее удалены все файлы (нельзя исключить те-
кущий и корневой каталоги). Например:
A)RO КАТ1<ВВОД>
Аргументами команды CD могут также быть: \ — для
перехода в корневой каталог и ..— для перехода в каталог
предшествующего уровня (с помощью этих двух точек
можно подняться только на один уровень, т. е. нельзя ста-
вить подряд четыре, шесть и более точек). Например:
А:\КАТ1>СР\<ВВОД>
A:\KAT1 >СР..<ВВОД>
Рассмотрим примеры организации некоторой файловой системы.
Предположим, что в корневом каталоге необходимо создать два под-
каталога WORK и TEXT, а в подкаталоге TEXT создать еще один под-
каталог РОС. Все это необходимо сделать на текущем диске В. Тогда
следует ввести команды:
В)МР WORK(BBOД)
В)МР ТЕХТ(ВВОД)
В)МО ТЕХТ\РОС (ВВОД)
Создадим теперь в подкаталоге РОС еще один — ОР:
B)MD ТЕХТ\РОС\РР(ВВОД)
Предположим, что в DD записан файл MINSK.TXT.
Здесь MINSK — имя файла, TXT — тип файла. Имя фай-
ла может включать от одного до восьми символов и содер-
жать буквы латинского алфавита от А до Z, цифры от
О до 9 и некоторые специальные символы, порядок следо-
вания которых не имеет значения. Запрещается исполь-
зовать символы +, = , [, ”, \, ], /, (, ), а также
* и ?, которые применяются в шаблонах. Тип, или расшире-
ние имени файла, может содержать не более трех символов
такого же вида.
Запись В: \TEXT\DOC\DD\MINSK.TXT г^ли \ТЕХТ\
DOC\DD\MINSK.TXT называется маршрутом к файлу
MINSK.TXT. Маршрут может быть задан из любого теку-
щего подкаталога (не обязательно из корневого). При
этом через знак \ перечисляются все иерархически
связанные подкаталоги, которые встречаются на пути сле-
дования к требуемому файлу.
Введем команду
В) СР TEXT)РОС (ВВОД)
После этого появится приглашение: B:\TEXT\DOC), и
текущим будет подкаталог DOC. Предположим, что файл
106
MINSK.TXT необходимо удалить (для этого используется
рассматриваемая в следующем параграфе команда DEL):
B:\TEXT\DOC>DEL DD\MINSK.TXT/ВВОД'>
Здесь символы ЭВ\указывают, что из текущего подката-
лога DOC сначала необходимо перейти в подкаталог DD,
и в нем уже найти файл MINSK.TXT, т. е. здесь задан
маршрут к файлу MINSK.TXT из текущего подкаталога
DOC.
Приведем еще некоторые команды:
B:\TEXT\DOC) СР\(ВВОД)
В)CD TEXT\DOC\DD (ВВОД)
B:\TEXT\DOC\DD)CD.. (ВВОД)
В:\ТЕХТ\РОС)СР..(ВВОД)
B:\TEXT)CD..\WORK(BBOfl)
В:\\УОИК)СР..\ТЕХТ(ВВОД)
В:(TEXT)RD DOC\DD(ВВОД)
В последней команде будет удален подкаталог DD,
если в нем не содержатся файлы.
Иногда удобно обращаться сразу к группе файлов, а
не работать с ними по отдельности. Для этого используют-
ся специальные конструкции, называемые шаблонами.
В них применяют символы * и ?. Звездочка (*) означает
любое число допустимых символов, а вопросительный
знак (?) — единственный символ в имени или типе файла.
Рассмотрим примеры: A:MINSK.TXT — файл MINSK.TXT
на диске А; A:*.TXT — все файлы, имеющие тип ТХТ на
диске А; В:*.* — все файлы на диске В; C1MRTI*.?? —
все файлы на диске С, имя которых начинается с символов
MRTI, а тип имеет ровно две буквы; M???.P?S — все
файлы, имя которых содержит четыре буквы и начинается
с М, а тип — три буквы (из них первая Р, последняя S,
а вторая — любая). Запись вида AiMINSK.TXT называет-
ся спецификацией файла и включает имя дискового нако-
пителя, имя и тип файла.
MS-DOS использует два способа доступа к файлам: че-
рез блок управления файлами (File Control Block —
FCB) и через дескриптор. FCB позволяет получить доступ
к файлам только в текущем каталоге. Это старый способ,
и сегодня он практически не применяется. Через дескрип-
тор можно получить доступ к любому файлу, вне зави-
симости от того, какой каталог текущий.
Перед началом работы с файлом он должен быть
открыт. Это означает создание специальной области с
107
информацией о файле и промежуточным буфером, через
который будут передаваться данные. В случае дескриптора
такая область помещается в любом месте. Затем ОС
строит 16-разрядный код номера, используемый далее для
выбора файла, с которым производится та или иная опера-
ция. Чтобы найти файл, создается строка (длиной до
63 байт), завершаемая ASCII-кодом нуля. В ней указы-
вается путь к файлу, структура которого уже рассматрива-
лась выше.
По окончании работы с файлом он должен быть закрыт.
При этом очищаются все системные буферы и остав-
шиеся данные пересылаются на диск. Одновременно обнов-
ляется информация в каталоге. Если не закрыть файл пе-
ред завершением программы, это может привести к потере
данных. Максимальное число одновременно открытых
файлов задается при конфигурировании системы (об этом
см. § 3.5). Каждому из них отводится место для блока
параметров и буфера. Эта память недоступна для про-
грамм пользователя, даже если указанное число файлов не
открыто. Поэтому для экономии памяти надо устанавли-
вать те значения, которые действительно необходимы.
В заключение приведем структуру блока управления
файлами (в круглых скобках указан размер соответствую-
щего поля):
1) номер накопителя: 0 — текущий, 1—А, 2—В и
т. п. (1);
2) имя (8 байт) и тип (3 байта) файла, которые
должны быть выровнены по левому краю и при необходи-
мости дополнены справа пробелами (11);
3) номер текущего блока. MS-DOS организует блочную
работу с файлами. Каждый блок содержит до 128 запи-
сей (2);
4) размер одной записи (в байтах), который по умол-
чанию равен 128 байтам (2);
5) размер файла с точностью до байта. Это'поле запол-
няет ОС при открытии файла (4);
6) дата создания или модификации файла, которая
записывается системой при его открытии (2);
7) зарезервированная область ОС (Ю);
8) номер текущей записи от 0 до 127 (2);
9) номер записи прямого доступа, который использует-
ся только при размере записи, меньшем 64 (4). Сюда зано-
сится требуемое значение, а поля текущих блока и записи
будут заполнены средствами ОС.
Для создания файла со специальными атрибутами
108
(скрытый файл или только для чтения) используется
расширенный блок управления файлами. Он дополнен
семью байтами, которые идут перед обычным блоком и со-
держат:
1) FFi6—однобайтный статус расширенного блока;
2) 5 байт с ASCII-кодом нуля;
3) байт атрибутов.
3.4. РЕЗИДЕНТНЫЕ КОМАНДЫ
И ВНЕШНИЕ УТИЛИТЫ
Команды ОС задаются в общем виде:
К x,...xn/a1.../a4
Здесь К — имя команды или программы (это обязатель-
ный элемент). Аргументы Xi, ..., XN требуются не во всякой
команде, и некоторые из них могут опускаться. То же самое
относится и к параметрам — указателям режима Ai, ...,
Ам. Аргументы обычно определяют те объекты, с кото-
рыми имеет дело данная команда: имена накопителей,
каталогов, файлов. Указатели режима (ключи) служат
для задания различных модификаций и режимов выпол-
нения команд
Резидентные команды выполняются интерпретатором
модуля COMMAND.COM. Для них не нужны другие про-
граммные средства. Большую группу составляют рези-
дентные команды для работы с файлами.
Для копирования файлов используется команда COPY
с аргументами. Первый из них определяет источник,
т. е. место, откуда копируется файл, второй — приемник,
т. е. место, куда копируется файл. Если диск с источником
либо диск с приемником не указан, подразумевается теку-
щий диск. Команда COPY позволяет также осуществлять
конкатенацию (объединение) файлов путем использова-
ния операции «~р». Она может применяться и для органи-
зации обмена данными с периферийными устройствами
путем указания их имени вместо имени соответствующего
файла.
Приведем некоторые логические имена, зарезервиро-
ванные за стандартными периферийными устройствами
ПЭВМ: PRN — основной принтер; LPT1 —другое имя
основного принтера; CON — консоль, т. е. клавиатура и
дисплей; LPT2 — дополнительный принтер (фактически
LPT1 и LPT2 именуют основной и дополнительный парал-
лельные каналы, к которым наиболее часто подключаются
принтеры); AUX—основной коммуникационный канал;
СОМ1 — другое имя основного коммуникационного кана-
109
ла; COM2 — дополнительный коммуникационный канал;
NUL — пустое устройство.
В команде COPY могут быть использованы следующие
ключи: /V — задает верификацию, т. е. проверку правиль-
ности копирования; /А — формат записи ASCII — тексто-
вые файлы; /В — формат записи двоичный — програм-
мные файлы.
Рассмотрим примеры:
1) A)COPY B:PR1.C D-.PRIMl .CI (ВВОД) — файл
со спецификацией B.PR1.C переписывается на диск D, и
ему назначается новое составное имя PRIM1.CI;
2) B)COPY PR1.C А:<ВВОД> — файл PR 1 ,С с диска
В переписывается на диск А с тем же именем;
3) A)COPY *.*С:(ВВОД) —копирование всех фай-
лов с диска А на диск С;
4) A)COPY В:*,С Р:*.С1(ВВОД) —копирование с
диска В всех файлов типа С на диск Р и назначение им
типа CI;
5) QCOPY F1.PAS Р2.Р(ВВОД) — получение на
диске С копии файла F1.PAS с составным именем F2.P;
6) A)COPY F1.C4-F2.C+F3.C F.C <ВВОД> — файл
с составным именем F.C образуется путем соединения фай-
лов Fl.C, F2.C и F3.C (если не указать F.C, то соответст-
вующие данные будут сохранены в файле, имя которого
указано первым, т. е. F1.C);
7) A)COPY PRIM.PAS PRN(BBOfl) — файл PRIM.
PAS выводится с диска А на принтер;
8) A)COPY CON ТТТ.С(ВВОД) — файл с состав-
ным именем ТТТ.С создается в результате копирования с
клавиатуры. Необходимо последовательно набирать тре-
буемые строки текста, каждая из которых завершается
нажатием клавиши ВВОД. По окончании набора текста
нажимаются клавиши УПР — Z (Ctrl — Z) и ВВОД;
9) А>сору c:Minsk.TXT (ВВОД)—файл Minsk.
TXT копируется с диска С на диск А (напомним, что можно
использовать в любом сочетании строчные и прописные
буквы).
Укажем некоторые другие действия, вызываемые на-
жатием клавиш:
УПР— ЦИФ—ПЭВМ переводится в режим паузы
(например для приостановки вывода на экран); пауза
заканчивается при нажатии любой клавиши, кроме СТОП,
ВСТ, УПР, ДОП и клавиш переключения регистров;
УПР — СТОП — происходит прерывание выполнения
программы и перевод ПЭВМ в режим ввода команд;
но
УПР — КОН — вызывает удаление символов на экра-
не, начиная с позиции курсора и до конца строки;
УПР — Р — устанавливается режим параллельного
вывода на экран дисплея и принтер;
УПР—4 — сдвиг курсора на слово влево (цифра 4 на-
бирается на малой цифровой клавиатуре);
УПР—6 — сдвиг курсора на слово вправо (цифра 6
набирается на малой цифровой клавиатуре);
ф (Shift — Tab) — перемещение курсора влево на
предшествующую позицию табуляции.
Содержимое текстового файла можно также вывести
на экран с помощью команды TYPE. Ее аргументом
должно быть имя конкретного файла (использование шаб-
лонов запрещается). Например:
A)TYPE D PROG FOR<BBOfl)
При этом на экран будет выведен файл PROG.FOR с
диска D.
Удаление файлов с диска осуществляется командой
DEL (ERASE). Например:
1) A) DEL C:COS.OBJ (ВВОД) — с диска С удаляет-
ся файл COS.OBJ;
2) В)ERASE*.BAS (ВВОД) — с диска В удаляются
все файлы, имеющие тип BAS.
Для переименования файлов используется команда
REN. Она изменяет имя файла, не затрагивая его содер-
жимого. В команде REN задаются два аргумента —
старое имя или шаблон и новое имя или шаблон. На-
пример:
1) A)REN ТТТ OLD RRRNEW(BBOД) — на диске
А файл с именем ТТТ.OLD переименовывается в файл
с именем RRR.NEW;
2) В) REN *.ААА *.ВВВ(ВВОД) — на диске В осу-
ществляется изменение всех файлов с типом ААА на
файлы с типом ВВВ.
Кратко рассмотрим другие резидентные команды.
Команда PATH устанавливает альтернативные маршруты
для поиска программ. Она может иметь или не иметь аргу-
менты. В первом случае аргументы перечисляются через
точку с запятой и указывают маршруты, где будет осу-
ществлен поиск вызываемой программы (только с типом
EXE, СОМ, ВАТ). Сначала эта программа будет разыски-
ваться на текущем диске, а при отрицательном результа-
те — по всем маршрутам, перечисленным через точки с
запятыми в команде PATH. Если ввести команду PATH
ill
без параметров, на экран дисплея будут выведены все
ранее заданные альтернативные маршруты поиска. Если
ввести команду PATH и сразу после нее точку с запятой
(PATH; (ВВОД) ), осуществляется сброс всех установлен-
ных ранее альтернативных маршрутов поиска. Например:
1) А)РАТН A:\;B:\;C:\;KAT\WORK (ВВОД) — ус-
танавливаются альтернативные маршруты поиска на
дисках А, В и в подкаталоге WORK подкаталога КАТ
диска С;
2) В)РАТН А:\РО5(ВВОД> — устанавливается
единственный альтернативный маршрут поиска в подката-
логе DOS диска А.
Команда SET позволяет вводить в окружение ОС раз-
личные имена с параметрами, которые затем могут исполь-
зоваться прикладными программами. Она задается в двух
формах: 1) SET и 2) SET name-text.
Первая группа позволяет вывести на экран дисплея те-
кущие установки MS-DOS, которые будут отображаться
вместе с любыми сделанными установками. Вторая форма
позволяет задать собственные установки. Здесь пате —
комбинация символов клавиатуры (длиной до 121 симво-
ла); text — один или несколько перемещаемых парамет-
ров (длиной до 121 символа). Например:
В > SET WORK-= A:\KAT < В В О Д >
Здесь вводится имя WORK с параметром A:\KAT, кото-
рое является указанием для некоторых программ, где
следует брать вспомогательные файлы. Команда
В > SET WORK= < В ВОД)
отменяет сделанную установку.
Команда PROMPT задает формат приглашения ОС.
Ее аргументами являются пары символов, первый из кото-
рых — знак $. В качестве таких аргументов можно исполь-
зовать:
$$ — выдача символа $;
$_ —возврат каретки (начинает новую строку);
$Ь —выдача символа разделителя1!;
$е — выдача символа ESC;
$h — стирание предыдущего символа;
$g — выдача символа разделителя);
$1 — выдача символа разделителя <;
$п — выдача логического имени текущего накопителя;
$р — выдача имени текущего каталога;
$q — выдача символа разделителя =;
112
$t — выдача текущего времени;
$d — выдача текущей даты;
$v — выдача номера версии MS-DOS;
$ Н—те же действия, что и при нажатии клавиши
Ноте.
Например:
A) PROMPT $п$Ь(ВВОД)
После этого будет выдано следующее приглашение: А];
A) PROMPT $p$d$q < В ВО Д >
После этого будет выдано следующее приглашение: А(
установленная дата ) = .
MS-DOS поддерживает область памяти, содержащую
набор строк с символами ASCII-кода, каждая из которых
завершается нулевым байтом. Эта область имеет размер
до 32 К байт и может использоваться для получения си-
стемной информации и передачи данных между програм-
мами. Для ее наполнения служат команды PATH,
PROMPT и SET, которые задают удобное окружение ОС.
Адрес параграфа описанной области хранится в PSP теку-
щей программы по смещению 2Cjf> (см. об этом в § 3.6).
Команда CLS используется для очистки экрана. На-
пример:
А)С15<ВВОД)
ПО КОМАНДЕ DATE выдается сообщение о текущей
дате и запрос на установку новой даты. При необходи-
мости такую установку следует задавать в строгом соот-
ветствии с форматом, указанным на экране (можно просто
нажать клавишу ВВОД).
По команде TIME выдаются сообщение о текущем
времени и запрос на установку нового времени. При необ-
ходимости такую установку нужно задавать в строгом
соответствии с форматом, указанным на экране (можно
просто нажать клавишу ВВОД).
Команда VER используется для получения информа-
ции о версии MS-DOS.
Команда VOL служит для вывода метки диска, коман-
да LABEL— для задания метки диска.
Команда BREAK устанавливает (ON) и отключает
(OFF) прерывание программы при нажатии клавиш
УПР — СТОП (Ctrl — Brk). Команда VERIFY устанавли-
вает (ON) и отключает (OFF) верификацию (проверку)
при записи данных на диск. Если ввести BREAK и VERIFY
113
без параметров, то выводится их статус (текущая уста-
новка) .
Рассмотрим некоторые внешние утилиты системы MS-
DOS. При этом будем подразумевать, что файл с соответ-
ствующей утилитой находится на том диске, который ука-
зан как текущий.
Утилита FORMAT осуществляет начальную разметку
(форматирование) дисков. Она применима к гибким и
жестким дискам. В случае использования жестких дисков
их необходимо предварительно подготовить с помощью
утилиты FDISK (эта процедура часто выполняется на
заводе-изготовителе). При форматировании происходит
разрушение всей ранее записанной на диске информации.
Аргументом утилиты FORMAT является имя накопите-
ля, на котором установлен форматируемый диск. Напри-
мер:
A)FORMAT В-(ВВОД)
При таком обращении пользователю выдается сообще-
ние о необходимости установки на накопитель В форма-
тируемого диска. Затем, после нажатия клавиши ВВОД,
начинается форматирование, которое для гибкого диска
продолжается около 1 мин. Вместе с командой FORMAT
можно использовать следующие ключи:
/V — указывает на необходимость задания метки дис-
ка, которая вводится пользователем по окончании форма-
тирования;
/S — указывает на необходимость переноса на форма-
тируемый диск трех файлов: IBMBIO.COM, IBMDOS.
СОМ, COMMAND.COM;
/В — на диске резервируются места для файлов ОС
без их переноса;
/1 —одностороннее форматирование (по умолчанию,
форматируются обе стороны диска);
/4 — форматирование с высокой плотностью;
/8 — форматирование по 8 секторов на дорожке (по
умолчанию, форматируются 9 секторов на дорожке);
/N:xx — указывает число секторов (хх), которое необ-
ходимо форматировать на одной дорожке;
/Т:уу — указывает число дорожек (уу), которое необ-
ходимо форматировать.
Например:
В) FORMAT A:/S/V(ВВОД)
Здесь на диск А после форматирования будут перенесены
три файла ОС и запрошена метка диска.
114
Утилита SYS позволяет перенести с текущего систем-
ного диска на диск, указанный в качестве аргумента,
два файла ОС: IBMBIO.COM и IBMDOS.COM. При этом
указанные файлы становятся скрытыми (они не показы-
ваются командой DIR).
Утилита APPEND подобна команде PATH. Она также
задает альтернативные маршруты поиска. Однако в отли-
чие от PATH, которая действует только на файлы с типами
COM, EXE, ВАТ, APPEND позволяет работать с любыми
файлами. Например:
А > APPEND C:\WORK;A:\<B В О Д >
Команда вида
А> APPEND<ВВОД>
отображает на экране дисплея текущие установки. Ко-
манда
A) APPEND;<BBOfl)
отменяет действие этой утилиты.
Утилита ASSIGN позволяет переустанавливать логи-
ческие имена физических дисковых накопителей. Она мо-
жет быть использована в следующих формах:
1) ASSIGN П1 = ГП| . n/,= rm;
2) ASSIGN.
Например:
А > ASSIGN А=С В=Р < В В О Д >
все обращения к накопителю А заменяет на обращения к
накопителю С, а все обращения кВ — на обращения к D.
Команда
A>ASSlGN<BBOfl>
исключает все ранее сделанные переустановки.
Утилита ATTRIB изменяет или отображает на экране
дисплея атрибут файла. В ней можно использовать сле-
дующие параметры:
+ R — файл будет доступен только для чтения;
— R — снятие установки «только для чтения»;
4-А — устанавливает архивный атрибут;
— А — снятие установки архивного атрибута.
Например:
А > ATTRIB \KAT\WORK\MRT1.C < В В О Д >
В этом случае, если файл MRTI.C в подкаталоге WORK
115
подкаталога КАТ диска А доступен только для чтения, в
появившейся строке на экране первой буквой будет R
(R A:\KAT\WORK\MRTI.C);
А > ATTRIB +R *-С < В В О Д >
для всех файлов диска А с типом С устанавливает защиту
записи;
А > ATTRIB —R кС < В В О Д >
для всех файлов диска А с типом С снимает защиту записи.
Улита AVERIFY проверяет правильность выполне-
ния утилиты BACKUP. Допускается применение следую-
щих конструкций:
1) AVERIFY — для получения информации на экране
дисплея о командах этой утилиты и их параметрах;
2) AVERIFY(источник данных) (приемник данных)
(ключи) OLD-NEW.
В качестве ключей можно использовать:
/s,/r,/n,/f— по аналогии с утилитой BACKUP (см.
ниже);
/р,/о — по аналогии с утилитой RESTORE (см. ниже);
/Ь — имеет стиль ВАТ файла. Проверяет процесс без
информирования пользователя.
Например:
В > AVERIFY С: АД < В ВО Д >
позволяет проверить правильность переноса данных с
жесткого диска С на гибкий диск А;
В AVERIFY A: C:\WORK\*.COM(BBOfl)
проверяет правильность переноса всех файлов типа СОМ
в подкаталоге WORK диска С.
Утилита BACKUP используется для копирования дан-
ных с одного диска на другой в упакованном виде (соот-
ветствующая распаковка осуществляется"1 утилитой
RESTORE). Допускается применение следующих конст-
рукций:
1) BACKUP — для получения информации на экране
дисплея о командах этой утилиты и их параметрах;
2) BACKUP (источник данных) (приемник данных)
(ключи).
В качестве ключей можно использоваь:
/т — для переноса только тех файлов, которые были
модифицированы после последнего выполнения утилиты
BACKUP;
116
/А — для переноса только тех файлов, которые были
модифицированы после указанной даты (она задается в
виде: /d:/d:mm—dd—уу или /d:dd—mm—уу, где dd —
день, mm — месяц, уу — год;
/а — добавляет новые файлы к существующим на
приемном диске (этот ключ наиболее часто используется
с ключом /т);
/s—позволяет учитывать подкаталоги выбранного
каталога;
/г—копирование только файлов в каталоге (файлы
из подкаталогов не копируются);
/п — выполняются действия утилиты BACKUP, но
файлы не записываются (этот ключ полезен для проверки
того факта, что введенная команда выполняет желаемые
действия);
/f — указывает размер и дату создания либо послед-
ней модификации файла;
/v — проверяет правильность копирования файлов.
Например:
В > BACKUP СДА; ( В В ОД >
осуществляет копирование содержимого жесткого диска С
на гибкий диск А;
В > BACKUP СД А:/т/а < В В О Д >
производит копирование тех файлов, которые изменены
с момента последнего выполнения утилиты BACKUP, они
добавляются к существующим файлам на диске А;
В > BACKUP СД WORK\*EXE А;< В В О Д >
осуществляет копирование всех файлов типа EXE из под-
каталога WORK диска С на диск А;
В > BACKUP С: А:/п< В В О Д >
выполняет проверку правильности (ключ /п) этой ко-
манды.
Утилита CHKDSK проверяет информацию на диске и
выдает сведения об использовании дисковой памяти. Вме-
сте с ней могут быть использованы ключи:
/v —для выдачи отчета об имеющихся ошибках;
/f — для исправления ошибок в оглавлении и таблице
размещения файлов.
Например:
А)СНКР5К<ВВОД)
выдает подробные сведения об использовании дискового
117
пространства. Следующая строка позволяет получить
информацию о всех файлах на диске:
А)СНКР5К/у(ВВОД)
Утилита СОМР сравнивает два файла и выдает све-
дения об обнаруженных расхождениях. Если их нет, будет
выдано сообщение ’’Files compare ok”. Например:
А> COMP ААА.С ВВВ.С < В В О Д >
сравнивает два файла: ААА.С и ВВВ.С.
Утилита CTTY позволяет менять рабочие устройства
ввода-вывода. Например:
A)CTTY АЦХ(ВВОД)
используется для передачи управления вводом-выводом
другой ПЭВМ. Обычно эту утилиту применяют в команд-
ных файлах, поскольку она делает недоступным ввод с
клавиатуры.
Утилиты DISKCOMP и DISKCOPY применяются для
сравнения и копирования дисков (при необходимости в
DISKCOPY сначала выполняется форматирование). Их
аргументами являются логические имена дисков. На-
пример:
А > DISKCOPY В:С: < В В О Д >
Здесь вся информация с диска В будет перенесена на
диск С. Использование ключа /1 вызывает сравнение (ко-
пирование) одной стороны.
Утилита FDISK позволяет выделить на винчестере до
четырех логических дисков. Выбор нужных действий осу-
ществляется с помощью меню на экране. При создании
логического диска необходимо указать его номер, статус
(А — активный, N — нет), тип (DOS или нет) и размеще-
ние (начальный цилиндр и размер).
Утилита FIND осуществляет поиск описанного фраг-
мента текста в файле. Она может использов'аться со сле-
дующими ключами:
/v — для отображения строк, не содержащих задан-
ный текст;
/п — указывает относительный номер каждой строки;
/с — отображается число строк, совпадающих с задан-
ной строкой.
Ключи /п и /с не должны использоваться одновре-
менно.
Общий синтаксис применения утилиты FIND можно
представить в следующем виде:
118
FIND (ключи) ’’искомый текст” (файл или несколько файлов, в которых
осуществляется поиск, через пробел)
Например:
А)FIND/v "Minsk" MRTI.TXT BGU.TXT (ВВОД)
Здесь будут выбираться все строки, не содержащие слово
--Minsk” в файлах MRTI.TXT и BGU.TXT.
Утилита GRAFTABL загружает таблицу символов рус-
ского алфавита (ASCII-коды от 128 до 255) для работы
в графическом режиме. Например:
А)GRAFTABL(ВВОД)
Утилита GRAPHICS используется для выдачи на прин-
тер графической копии экрана. При этом возможны три
варианта:
1) если экран находится в текстовом режиме (0—3,7),
вывод происходит так же, как и без утилиты GRAPHICS;
2) если экран находится в режиме 4 или 5 (320X200
точек), на экран выводятся текст и графические изобра-
жения;
3) если экран находится в режиме 6 (640 X 200 точек),
изображение выводится на принтер повернутым на 90°.
. После вызова команды GRAPHICS и нажатия клавиш
— ПЕЧ (Shift — Prt-Sc) темные точки экрана стано-
вятся на бумаге белыми и наоборот. Чтобы инвертировать
изображение на бумаге, необходимо задать ключ /R:
А ) GRAPHICS/R( В В О Д )
Утилита MODE задает режимы работы принтера, ком-
муникационного адаптера и экрана дисплея. Она может
использоваться в следующих формах.
1. MODE LPTn:c,l,p. Здесь п — номер порта для прин-
тера (1,2 или 3); с— задает 80 или 132 символа в строке;
I — задает 6 или 8 строк на дюйм (25,4 мм); р — указы-
вает на то, что MODE будет постоянно пытаться переслать
выходные данные на принтер при ошибке. По умолчанию,
задается LRT1 с 80 символами в строке и 6 строками на
дюйм.
2. MODE COMn:b,pp,d,s,p. Здесь п —номер последо-
вательного порта (1 или 2); b — скорость передачи дан-
ных (НО, 150, 300, 600, 1200, 2400, 480 или 9600 с"1);
рр — определяет способ контроля передачи данных (Е —
на четность, О—на нечетность, N — отсутствие провер-
ки); d — задает 7 или 8 бит данных в одной посылке;
119
s — определяет число стоп-битов (1 или 2); р — указы-
вает, что порт СОМп используется для последовательного
принтера и при ошибке должны предприниматься повтор-
ные попытки передачи данных.
3. MODE LPTn: = COMm — для переназначения па-
раллельного принтера с номером п на последовательный
порт с номером т.
4. MODE d. MODE d,s. Здесь d— параметр, указы-
вающий способ отображения информации на экране дисп-
лея: 40 — сорок символов в строке; 80—восемьдесят
символов в строке; BW40, СО40 — сорок символов в стро-
ке для цветного графического экрана; BW80, СО80 —
восемьдесят символов в строке для цветного графического
экрана; MONO — монохромный дисплей с 80 символами в
строке. Аргумент s определяет направление, на которое
желательно сдвинуть изображение: либо R (вправо), либо
L (влево).
Кроме того, утилита MODE позволяет менять скорость
работы микропроцессора Intel 80386 (для 32-разрядных
ПЭВМ) и копировать некоторые модули BIOS из ПЗУ в
высокоскоростную оперативную память. Например;
А>MODE MONO (ВВОД)
задает режим работы монохромного дисплея;
А)MODE СОМ1: 9600,N,7,2(ВВОД)
настраивает последовательный порт 1 на.скорость 9600 с-1
(здесь можно ограничиться указанием только двух цифр,
т. е. 96), без проверки, с передачей в одной посылке 7 бит
данных, при наличии двух стоп-битов;
А)МОРЕ LPT1: 132,8 (ВВОД)
устанавливает режим работы первого принтера (LPT1):
132 символа в строке и 8 строк на дюйм;
А)МОРЕ BW40,L,T(BBQfl) ,,
устанавливает экран в режим с 40 столбцами; разрешает-
ся сдвиг его изображения влево с использованием тесто-
вого образца (Т) для помощи в выравнивании.
Утилита MORE работает как фильтр. Ей на вход необ-
ходимо передать текстовой файл, который она выдает на
стандартное устройство вывода (экран дисплея) порциями
по 24 строки. Например:
A)MORE (MRTI.TXT(ВВОД)
файл MRTI.TXT выводится на экран указанными порция-
120
ми. Выдача очередной порции осуществляется после на-
жатия любой клавиши;
A)DIR1, МОЦЕ(ВВОД)
выдает порциями на экран содержимое корневого каталога
диска А.
Утилита PRINT обеспечивает постановку текстовых
файлов в очередь на печать, которая в этом случае произ-
водится на фоне любой другой задачи. Например:
А > PRINT FILE1.TXT FILE2.TXT FILE3.TXT < В В О Д >
Здесь файлы FILE1 .TXT,FILE2.TXT,FILE3.TXT ставятся в
очередь на печать, и если принтер свободен, то сразу же
начинается вывод файла FILE1.TXT. В команде PRINT
можно задавать следующие ключи:
/Q:max — задание максимального числа (max) фай-
лов (от 1 до 32) в очереди (по умолчанию, их 10);
/Г):р — задание имени принтера (р) или другого
устройства для вывода данного файла;
/В:Ь — задание размера буфера в байтах (по умолча-
нию, в буфере 512 байт);
/С — исключение из очереди данного файла и всех
последующих;
/Р — отмена действия ключа /С;
/Т — прерывание печати;
/U:t — задание числа циклов таймера для ожидания
доступа к принтеру;
/M:t — задание числа циклов таймера, которое PRINT
занимает для печати;
/S;t — задание числа циклов таймера для посылки на
принтер очередного символа.
Команда без параметров выводит на экран состояние
очереди печатаемых файлов.
Утилита RECOVER обеспечивает восстановление уда-
ленных или поврежденных файлов. Например:
А > RECOVER В:<В В О Д >
восстанавливает все удаленные файлы на диске В.
Утилита RESTORE восстанавливает (осуществляет
обратный перенос) файлы, упакованные утилитой
BACKUP. Допускается применение следующих конструк-
ций:
1) RESTORE — для получения информации на экране
дисплея о командах этой утилиты и их параметрах;
121
2) RESTORE (источник данных) (приемник данных)
(ключи) OLD-NEW.
В качестве ключей можно использовать:
/d,/s,/r,/n,/f — по аналогии с утилитой BACKUP;
/р — выдается запрос о восстановлении каждого фай-
ла с защитой от записи либо скрытого;
/о — для изменения имени старого каталога (OLD) на
новый (NEW);
/a:date—восстановление файлов, измененных после
указанной даты;
/d:date — восстановление файлов, измененных до ука-
занной даты;
/e:time — восстановление файлов, измененных до ука-
занного времени;
/l:time — восстановление файлов, измененных после
указанного времени.
Например:
В > RESTORE А: С.\ < В В О Д >
производит восстановлениесодержимого жесткого диска С
с гибкого диска А (см. утилиту BACKUP);
В > RESTORE A: C:\WORK\ /г< В В О Д >
восстанавливает все файлы в подкаталоге WORK, не
затрагивая подкаталоги более низкого уровня;
В > RESTORE A: C;\WORK\ /o:\WOR К\=\КАТ\< В В О Д >
заменяет подкаталог WORK на подкаталог КАТ.
Утилита SORT является фильтром и используется для
сортировки данных в файле. Ее применяют в следующих
форматах:
1) SORT (имя входного файла) имя выходного файла ключи;
2) команда ОС; SORT)имя выходного файла ключи.
Ключами могут быть:
/г — инверсия сортировки. Без этого клю^а сортировка
выполняется в соответствии с расположениём в строках
символов ASCII (от A kZ). Разница между прописными и
строчными буквами игнорируется. При наличии этого
ключа порядок сортировки меняется от Z к А;
/4~п — строки сравниваются, начиная с п-го символа
в каждой строке.
Например:
А)SORT(LIST,TXT (ВВОД)
строки файла LIST.TXT будут отсортированы и выданы на
экран дисплея;
122
A) SORT<LIST.TXT/+10 <ВВОД)
сортировка будет выполняться, начиная с десятого сим-
вола в каждой строке;
A) SORT(LIST.TXT)NAME ТХТ/+10 < в вод >
отсортированные строки будут направлены в файл
NAME.TXT;
A>DIR ] SORT(BBOfl)
на экран будет выведена отсортированная информация
корневого каталога диска А;
А > DIR'SORT/ + 10)PRN < В В О Д >
отсортированные данные корневого директория диска А,
начиная с десятой позиции каждой строки, будут выданы
на принтер.
Утилита TREE обеспечивает вывод на экран всех
путей к подкаталогам заданного диска. Если указать ключ
/F, то дополнительно выводятся и имена файлов в под-
каталогах. Например:
A)TREE/F(ВВОД)
Утилита XCOPY обеспечивает выборочное копирова-
ние групп файлов и поддиректориев. Соответствующие
конструкции подобны команде СОРУ. В качестве ключей
можно использовать:
/А — копирование файлов, у которых установлен
архивный бит, при этом он не изменяется;
/М — то же, что /А, но архивный бит сбрасывается в
нуль;
/D:mm-dd-yy — копирование файлов с указанной или
более поздней датой;
/Р — для каждого файла выводится запрос о необ-
ходимости копирования;
/S — копирование файлов и непустых поддиректориев
с файлами;
/Е — копирование также пустых поддиректориев
(обычно используется совместно с ключом /S);
/V — верификация в процессе копирования;
/W — копирование будет начато только после нажатия
клавиши.
Например:
A) XCOPY C:\A:/S/P( В ВО Д >
здесь будут копироваться все файлы (включая поддирек-
123
тории) диска С на диск А, и для каждого из них будет
запрашиваться подтверждение в виде (Y/N), т. е.
ДА/HET. В другом примере с диска А на диск В копи-
руются все файлы, созданные не ранее 26 февраля 1990 г.:
А>XCOPY A: B:/S/D:02-26-90(BВОД>
3.5. КОМАНДНЫЕ ФАЙЛЫ
И КОНФИГУРИРОВАНИЕ СИСТЕМЫ
Командные файлы являются выполняемыми, имеют
тип ВАТ и могут включать целую группу команд ОС или
обращений к прикладным программам, которые будут
реализовываться либо последовательно, либо в более
сложном порядке. Командный файл содержит текст, интер-
претируемый командным процессором ОС. Строками этого
текста могут быть:
1) резидентные команды ОС;
2) обращения к выполняемым программам;
3) вызовы других командных файлов;
4) команды для управления выдачей информации на
экран дисплея;
5) команды для организации ветвлений и циклов;
6) метки.
Пример командного файла FILE.BAT:
CD\KAT\WORK
MYPROG
CD\
Предположим, что FILE.BAT находится на диске А.
Тогда его запуск осуществляется так:
A)FILE <ВВОД>
В результате сначала будет осуществлен переход к
текущему подкаталогу WORK подкаталога КАТ диска А;
в этом подкаталоге будет выполнена программа MYPROG,
и, наконец, корневой каталог диска А стайет текущим.
. Еще один пример командного файла:
ECHO OFF
MODE MONO
PROMPT $p$g
PATH B:\;\DOS
DATE
TIME
ECHO текущий каталог WORK
CD\WORK
ECHO загружается программа MYPROG
MYPROG
PAUSE
124
ECHO загружается программа MRTI
MRTI
CD\
Предположим, что этот командный файл расположен
на диске В и имеет имя KF.BAT. Запустим его:
Р)КЕ<ВВОД)
В результате выполняются следующие действия:
1) команда ECHO OFF отключает выдачу на экран
дисплея последующих строк файла KF.BAT;
2) устанавливается режим работы монохромного дис-
плея;
3) устанавливается формат приглашения ОС;
4) задаются два альтернативных маршрута поиска в
корневом каталоге диска В и подкаталоге DOS диска А;
5) осуществляется выдача и установка текущей даты;
6) осуществляется выдача и установка текущего вре-
мени;
7) на экран выдается текст, указанный в команде
ECHO, т. е. «текущий каталог WORK»;
8) устанавливается текущий каталог WORK;
9) выдается сообщение «загружается программа
MYPROG»;
10) загружается из каталога WORK и выполняется
программа MYPROG;
11) команда PAUSE приостанавливает обработку
файла KF.BAT до нажатия любой клавиши (это может
потребоваться для анализа результатов программы
MYPROG);
12) выдается сообщение «загружается программа
МРТЬ;
13) загружается из каталога. WORK и выполняется
программа MRTI;
14) осуществляется установка текущего корневого
каталога (CD\).
В файлах типа ВАТ используется еще команда REM,
которая служит для внесения в текст комментариев. Стро-
ка, идущая следом за REM, является лишь пояснением
для пользователя и не интерпретируется командным
процессором. С помощью REM можно исключать выпол-
нение некоторых команд, не удаляя их из текста команд-
ного файла.
В файлах типа ВАТ разрешается использовать фор-
мальные параметры, которые начинаются знаком % и за-
125
канчиваются некоторым номером. Модифицируем рассмот-
ренный выше файл FILE.BAT:
CD\KAT\%1
% 2
CD\
Обозначения %1 и %2 использованы для формальных
параметров, вместо которых при обращении к FILE.BAT
будут подставлены фактические параметры, заданные в
командной строке. Например:
А > FILE WR MRTI < В ВОД >
здесь на место %1 будет подставлено фактическое имя
подкаталога WR, а на место %2 — MRTI. При другом
вызове могут быть подставлены другие фактические пара-
метры.
Рассмотрим действие более сложных команд, к числу
которых относятся GOTO, IF, FOR, SHIFT, EXIT.
Команда GOTO позволяет передавать управление на
указанную метку и осуществлять повторное выполнение
фрагментов командного файла. Например [4] :
:т
ECHO Вывод на принтер файла %1
COPY %1 PRN
PAUSE
GOTO М
Первая строка содержит метку m (ее признаком является
двоеточие в начале строки), последняя — команду пере-
хода на эту метку.
Предположим, что рассмотренный файл находится на
диске А и имеет имя PR.ВАТ. Если вызвать его следую-
щим образом:
A) PR MYPROG,TXT< ВВОД >
то на каждой итерации на принтер будет’’ выводиться
одна копия текста MYPROG.TXT. Здесь MYPROG.TXT —
фактический параметр, который подставляется вместо
формального параметра %1. Команда PAUSE дает воз-
можность сменить бумагу на принтере либо прервать
работу программы (для прерывания необходимо нажать
клавиши УПР — СТОП).
Команда IF позволяет анализировать заданное усло-
вие и выполнять последующие действия в зависимости
от результата его проверки. Существуют три модифика-
ции этой команды.
126
1. Проверка кода завершения программы, выполняе-
мой перед IF. Для этого используется конструкция
IF ERRORLEVEL <N>
Любая программа с помощью прерывания ОС может
выработать в момент своего окончания код завершения.
Он сравнивается с заданным числом N. Условие считается
выполненным, если код завершения больше или равен N.
2. Проверка наличия файла в каталоге:
IF EXIST <имя файла или шаблон>
Условие считается выполненным при обнаружении
файла в указанном либо в текущем каталоге.
3. Сравнение двух строк, которые могут задаваться
и через формальные параметры:
IF %<N> = — <текстовая строка>
Условие считается выполненным при совпадении
параметра %<N> с конкретной строкой.
Любое из приведенных условий можно задавать со зна-
ком логического отрицания NOT; отрицание условия счи-
тается выполненным, если само условие ложно.
Рассмотрим пример строки командного файла:
IF EXIST PROG.С TYPE PROG.С
Здесь, если в текущем каталоге имеется программа
PROG.С, ее текст будет выведен на экран дисплея.
Приведем еще одну строку:
IF %1 == stroka GOTO MET
Здесь, если фактический параметр, подставленный на
место %1, есть stroka, будет осуществлен переход к мет-
ке МЕТ.
Команда FOR осуществляет повторение фрагмента
командного файла заданное число раз. Она имеет следую-
щую форму записи:
FOR % % (имя переменной) IN (список значений переменной, разде-
ленных пробелом) DO (команда)
Например:
FOR %%В IN (*.ВАТ) DO TYPE %%В
Здесь команда TYPE будет выполняться для каждого
файла в текущем каталоге, имеющего тип ВАТ.
Приведем еще один пример: ।
FOR %%А IN (С OBJ EXE PRJ) DO COPY PROG.%%A В;
127
Здесь все файлы с именем PROG и типом С, OBJ, EXE,
PRJ будут скопированы с текущего диска на диск В.
Команда SHIFT вызывает сдвиг списка формальных
параметров относительно списка фактических параметров.
Предположим, что требуется отпечатать на принтере тек-
стовые файлы, имена которых будут указываться в виде
фактических параметров. Тогда можно создать следую-
щий командный файл (назовем его FPR.BAT):
:т
COPY %1 PRN
SHIFT
PAUSE
GOTO in
Предположим, что этот файл находится на диске А.
Запишем следующую команду:
A >FPR Fl,TXT F2.TXT F3 TXT < В В О Д >
На каждой итерации, определяемой командой GOTO,
будет осуществляться печать текста соответствующего
файла. Формальный параметр %1, согласно команде
SHIFT, будет последовательно принимать фактические
значения :F1.TXT, F2.TXT и F3.TXT. После исчерпания
списка фактических параметров команда COPY выдает
сообщение об ошибке, поскольку ее первый аргумент
будет отсутствовать. В это время можно прервать работу
командного файла, нажав клавиши УПР — СТОП.
Рассмотрим вложенные вызовы командных файлов.
Предположим, что из файла 1ST.ВАТ необходимо вызвать
файл PR.ВАТ, выполнить его и вернуться в 1ST.ВАТ.
Вложенные вызовы с возвратом возможны лишь при
создании копии командного процессора COMMAND.COM.
Вызов PR.ВАТ в файле 1ST.ВАТ должен осуществляться
так: COMMAND/C PR, а при возврате в файл^ PR.ВАТ
должна появиться строка EXIT. Следует иметь в виду,
что при вызове каждой копии командного процессора
дополнительно расходуется около 4 К байт оперативной
памяти.
Существует специальный командный файл автоза-
пуска AUTOEXEC.BAT. Он выполняется автоматически
при начальном запуске и инициализации ОС (следом за
файлом CONFIG.SYS). В связи с этим в файле
AUTOEXEC.BAT, который должен быть помещен в корне-
вом каталоге системного диска, целесообразно исполь-
зовать команды для настройки ОС на привычную для
пользователей операционную обстановку. В этом файле
128
удобно использовать команды PROMPT, PATH, SET,
загружать требуемые знакогенераторы для принтера
и дисплея и т. п.
Рассмотрим конфигурирование системы, которое осу-
ществляется с помощью файла CONFIG.SYS. В нем
можно использовать следующие команды.
1. BREAK=ON — для установки возможности пре-
рывания выполняемой программы при нажатии клавиш
УПР — СТОП (Ctrl — Break); BREAK = OFF — для от-
мены такой возможности.
2. BUFFERS = (М) —для установки максимального
числа М (2^М^99) буферов, используемых при обме-
не информацией с дисковыми накопителями (по умол-
чанию, М=2). На каждый буфер отводится 512 байт
оперативной памяти. Рекомендуется задавать следующие
значения М: для ПЭВМ только с гибкими дисками М= 4;
для модели АТ с 20—30-мегабайтным твердым диском
М=32.
3. СОиЫТРУ=код страны — установка формата да-
ты, времени и денежной единицы для заданной страны
(по умолчанию, принимается код 001 для США).
4. DEVICE= (маршрут и составное имя файла с но-
вым драйвером для внешнего устройства) — для под-
ключения к ОС драйверов новых внешних устройств, на-
пример виртуального диска, манипулятора типа «мышь»,
улучшенного принтера, драйвера ANSI.SYS и т. п. Команд
такого вида в файле CONFIG.SYS может быть сколько
угодно.
5. FCBS= — для задания числа блоков управления
файлами (FCB), которые могут быть открыты одновре-
менно. Сегодня эта команда используется довольно редко,
в связи с чем ограничимся лишь упоминанием о ней.
6. FILES = (N) — для установки максимального чис-
ла N (5s^Ns^99) одновременно открытых файлов (по
умолчанию, N = 8). Для большинства приложений можно
задавать значение N=20.
7. LASTDRIVE=d — устанавливает последнее логи-
ческое имя диска d (A^d^Z). По умолчанию, d=E.
8. SHELL = (имя файла с новым командным процес-
сором) — для указания имени файла с новым командным
процессором вместо стандартного файла COMMAND.
СОМ.
9. STACK=F, S — для решения проблемы реенте-
рабельности и обслуживания прерываний от оборудова-
ния. Здесь F —число порций стека, распределяемых ОС
5 Скляров В. А.
129
(8^F^64; по умолчанию, F=9); S — размер каждой
порции в байтах (32^8^512; по умолчанию, S = 128).
При каждом прерывании от оборудования ОС распре-
деляет его обработчику стековый фрейм. По окончании
этого процесса стековый фрейм возвращается в общий пул.
Пример файла CONFIG.SYS:
BREAK= ON
FILES = 20
BUFFERS=32
DEVICE= A\SYS\ANSI.SYS
DEVICE = A;\DRV\MOUSE SYS
DEVICE= A:\SYS\VDISK.SYS 128 512 1 00/E
Здесь предполагается, что файлы ANSI.SYS и VDISK.
SYS находятся в поддиректории SYS диска A, a MOUSE.
SYS — в поддиректории DRV диска А. Для драйвера
виртуального диска VDISK-SYS задано: 128 — объем вир-
туального диска в килобайтах (по умолчанию, 64); 512 —
размер сектора в байтах (допустимые значения — 128,
256, 512; по умолчанию, 128); 100—максимальное число
элементов в корневом директории (по умолчанию, 64);
/Е — ключ, требующий размещения диска в расширенной
памяти (extended memory). При отсутствии расширенной
памяти ключ /Е опускается. После ключа /Е может
задаваться максимальное число секторов, считываемых
или записываемых одновременно (допустимые значения —
1—8; по умолчанию, 8).
Таким образом, файлы CONFIG.SYS и AUTOEXEC.
ВАТ предназначены для предоставления пользователю
удобной рабочей обстановки. Эти файлы могут быть созда-
ны с помощью любого текстового редактора.
3.6. ПРОГРАММЫ ТИПА СОМ И ЕХЕ
Программы, работающие под управлением MS-DOS,
делятся на два основных класса: типа СОМ, имеющие
максимальный объем 64 К байта, и типа ЕХЕ, которые
могут занимать всю доступную память [18]. Примени-
тельно к МП Intel 8086 программы типа СОМ создаются
для малых моделей памяти (small), когда все сегментные
регистры содержат одно и то же значение. Программы
типа ЕХЕ могут быть созданы для средних (medium)
или больших (large) моделей, в которых сегментные
регистры содержат различные значения. Программы типа
СОМ размещаются на внешних носителях в том виде,
в котором они загружаются в оперативную память ПЭВМ.
130
При этом не требуются какие-либо дополнительные дан-
ные. В отличие от них программы типа EXE содержат
специальный заголовок с таблицей загрузки, используемой
MS-DOS.
Программы обоих типов загружаются для выполнения
с использованием одного и того же механизма, обеспе-
чиваемого модулем «загрузчика». Сначала строится пре-
фикс программного сегмента (Program Segment Prefix —
PSP), затем записывается текст модуля и устанавли-
ваются сегментные регистры. Первоначально модулю
выделяется вся доступная память, далее он сам должен
распоряжаться ею (освобождать часть памяти для другого
процесса и т. п.). Когда программа завершается либо
исключается средствами ОС, память освобождается, и мо-
жет быть загружен новый модуль.
Префикс программного сегмента (PSP) имеет размер
256 байт (1001б) и содержит сведения, необходимые ОС.
Поля PSP включают такие данные (в конце каждого
пункта в круглых скобках указаны смещение от нача-
ла PSP и размер в байтах соответствующего поля):
1) номер функции ОС для завершения программы
(обычно int 20Н). Когда выполняется последний оператор
загруженного модуля, управление передается на начало
PSP (0,2);
2) размер доступной памяти системы в парагра-
фах (2,2);
3) резервную область (4,2);
4) вызов типа far функции диспетчера ОС (6,4);
5) адрес завершения CS. IP (А[6,4);
6) адрес (CS:IP) обработки Ctrl — Break (Ei6,4);
7) адрес обработчика критических ошибок (12|6,4);
8) резервную область (16i6,22);
9) сегментный адрес (номер параграфа) окруже-
ния ОС (2С16,2);
10) резервную область (2Ei6,46);
11) область первого блока управления файлами (5Cie,
16);
12) область второго блока управления файлами
(6С16,20);
13) область передачи данных (Disk Transfer Area —
DTA). По умолчанию, здесь записывается командная
строка программы (80i6,128).
Любая загружаемая программа помещается в млад-
шую область памяти следом за COMMAND.COM и рези-
дентными модулями. В момент получения управления
131
в программе ЕХЕ-формата DS и ES указывают на PSP;
CS, IP, SS и SP содержат значения, заданные в заго-
ловке модуля. Вся доступная память отведена программе.
Программы типа СОМ предпочтительнее программ типа
EXE для небольших ассемблерных утилит. Они быстрее
загружаются, так как не требуют перемещения сегментов,
и занимают меньше места на диске, поскольку в загрузоч-
ном модуле отсутствует заголовок. В программе СОМ-
формата CS, DS, ES, SS указывают на PSP; SP адресует
конец сегмента (обычно FFFEig или меньшее значение,
если полный сегмент недоступен); IP содержит lOOig для
перехода на первый байт выполняемого модуля. Вся па-
мять системы за программным сегментом выделена про-
грамме. Заметим, что программа типа СОМ может исполь-
зовать различные сегменты, но она должна сама вы-
числять соответствующие адреса, используя PSP в ка-
честве базы.
MS-DOS имеет возможность динамически распреде-
лять память и выделять по требованию программы блоки
любого допустимого размера. Выше уже говорилось, что
сначала загруженная программа забирает всю память.
Поэтому на первом шаге существующий блок должен
быть сокращен до действительного размера программы.
Далее для каждого созданного блока MS-DOS строит
16-байтный управляющий блок (Memory Control BLock —
МСВ). В нем записываются такие сведения (как и выше,
в скобках указаны смещение и размер соответствующего
поля):
1) байт статуса. Если в нем записано 4Die, то за ним
есть другие блоки; если записано 5А|6, то блок послед-
ний (0,1);
2) указатель на PSP программы, которой принадле-
жит этот блок. Если блок свободен, то здесь содержится
нуль (1,2);
3) число параграфов в блоке (3,2); ’
4) резервная область (5,11);
5) начало области памяти, которое, в частности, возв-
ращает функция динамического выделения памяти MS-
DOS (1016, размер равен произведению содержимого
поля 3 и числа 16).
Все блоки памяти выравниваются по границе пара-
графа. ОС обращается к ним по цепочке. Адрес первого
блока содержится во внутренней переменной. Последую-
щий блок находится путем смещения на размер и заголо-
вок текущего блока. Освобождение блоков выполняется
132
с конца цепочки. Любая программа должна освободить
все выделенные ей блоки перед завершением, иначе они
будут недоступны для последующего использования.
По своей структуре программы типа СОМ значительно
проще. Их загрузка сводится к перемещению модуля
в требуемую область памяти и передаче управления по
смещению 10016 (для пропуска PSP). Однако размер
программ типа СОМ ограничен 64 К байтами. Программы
типа ЕХЕ имеют больше возможностей. Файлы стандарт-
ного ЕХЕ-формата на диске начинаются с такого заголов-
ка (как и выше, в скобках указаны смещение и размер
в байтах соответствующего поля):
1) 2) значения 4Di6, длина неполной 5А16 — признак типа последней страницы ЕХЕ L поел (0,2); (2,2);
3) длина файла в 512-байтных страницах 4) число элементов в таблице перемещения N, 5) длина заголовка в параграфах L3 (8,2); 6) минимум памяти в параграфах за концом граммы МШ|„ (А|6,2); (4,2); (6,2); про-
7) максимум памяти в параграфах граммы Mmax (Ci6,2); за концом про-
8) значение для установки регистра SS (Ei6,2);
9) значение для регистра SP при запуске (1016,2);
10) контрольная сумма для файла (12i6,2);
11) значение для регистра IP при запуске (1416,2);
12) значение для регистра CS (16[6,2);
13) смещение в ЕХЕ-файле для первого элемента
перемещения 1п — обычно ICie (18i6,2);
14) номер оверлея со значением нуль для головного
модуля (1А|6,2);
15) порция заголовка (смещение 1С1б).
Далее идет таблица перемещения, начало которой
определяется смещением 1п. Она имеет N3 4-байтных
элементов, включающих сегмент и смещение. После таб-
лицы идут пропуск до границы параграфа и далее сама
программа. «Загрузчик» ЕХЕ-файла выполняет такие
действия:
1) создает PSP;
2) читает порцию заголовка в локальную область
памяти;
3) определяет размер модуля: 512ЕФ— 16L3 (здесь
может быть учтено и значение Lnoc„);
4) определяет смещение в файле загружаемого мо-
дуля (16L3);
133
5) выбирает сегментный адрес для загрузки;
6) считывает модуль по выбранному сегментному ад-
ресу;
7) устанавливает указатель на начало таблицы пере-
мещения;
8) для каждого элемента перемещения определяет
его действительные адреса в памяти ПЭВМ с привязкой
к выбранному сегментному адресу модуля;
9) в соответствии со значениями Mm,n и Мтах выпол-
няет распределение памяти;
10) осуществляет начальную установку регистров ES,
DS, SS, SP, CS, IP и запуск программы.
Модули типа EXE при необходимости можно преоб-
разовать в тип СОМ. Делается это с помощью утилиты
EXE2BIN.EXE. При этом нужно придерживаться таких
правил:
1) программу не следует оформлять в виде процедуры;
2) значения DS, ES и SS должны совпадать с CS;
3) в начале программы на языке ассемблера поме-
щается оператор ORG 100Н для пропуска области PSP;
4) нельзя использовать установки сегментов вида:
mov ах, nseg mov ds, ах;
5) стековый сегмент должен быть полностью опущен
(предупреждение компоновщика об отсутствии стека сле-
дует игнорировать);
6) программа должна быть завершена либо коман-
дой RET, либо прерыванием 2016 (на самом деле это
одно и то же, так как в случае RET будет выполнен пере-
ход на начало PSP, где содержится вызов этого преры-
вания) .
Пусть, например, с использованием перечисленных правил создан
файл MY.EXE. Далее необходимо осуществить требуемое преобразо-
вание:
A>EXE2BIN MY МУ.СОМ<ВВОД>
Здесь предполагается, что утилита EXE2BIN и программа MY находят-
ся на диске А. Если выполнить другую команду:
А > EXE2BIN MY < В В О Д >
будет получен файл MY.BIN, и его следует переименовать в файл
MY.COM.
3.7. УСТАНАВЛИВАЕМЫЕ ДРАЙВЕРЫ УСТРОЙСТВ
Драйвер — это специальная программа, которая управ-
ляет обменом информацией с периферийными устройствами.
134
Он может быть установлен при загрузке ОС с помощью
файла CONFIG.SYS. В ОС существует прерывание (21 ie,
функция 44|б) для контроля ввода-вывода (IOCTL),
которое позволяет программе пользователя определить
состояние драйвера и передать ему управляющую строку.
После установки программа работает с поддержи-
ваемым устройством очень просто. Если таким устройст-
вом является графопостроитель, то ему может быть при-
своено имя, например PLOT (по аналогии с CON, PRN,
AUX и т. п.). Далее можно использовать это имя в раз-
личных командах, таких, как
COPY C-.PLT.TXT PLOT <ВВОД>
Здесь предполагается, что файл PLT.TXT подготовлен
специально для выдачи на графопостроитель и находится
на диске С.
Устанавливаемые драйверы могут обслуживать два
типа устройств: блочные, обычно предназначенные для
дисковых накопителей, и символьные — для всего осталь-
ного. Блочные устройства обмениваются блоками данных,
поэтому одной из задач является их накопление. Приме-
ром их является драйвер виртуального диска VDISK.
В символьных устройствах организован побайтный обмен
(пример — драйвер ANSI.SYS). Именно эти драйверы
мы будем здесь рассматривать.
Программа драйвера устройства состоит из трех час-
тей: заголовка, который содержит имя устройства и све-
дения о других двух частях; стратегии, в которой хра-
нится информация о заголовке запроса,— специальной
области, создаваемой MS-DOS; обработчика прерываний,
осуществляющего непосредственное управление устройст-
вом.
Драйвер устройства имеет тип SYS. В отличие от
файлов формата СОМ в начале программы не надо
помещать инструкцию ORG 100Н, так как PSP здесь
не создается. ЕХЕ-файлы должны быть преобразованы
в COM-формат с помощью утилиты EXE2BIN и далее
переименованы в тип SYS. Драйвер описывается как
процедура типа far.
Заголовок драйвера имеет длину 18 байт и включает
следующие поля:
1) область, которая заполняется ОС при установке
драйвера. Под установкой понимается указание имени
драйвера в команде DEVICE= файла CONFIG.SYS.
Установленное устройство имеет преимущество перед
135
одноименным драйвером ОС. Сначала в этой области,
имеющей размер 4 байта, содержится значение
FFFFFFFFic. А после загрузки MS-DOS записывает
сюда стартовый адрес следующего драйвера. У послед-
него загруженного драйвера здесь остается значение
FFFFFFFFI6;
2) атрибут устройства размером два байта (бит 15:1 —
символьное устройство, 0 — блочное; бит 14: 1 — поддер-
живает IOCTL, 0— не поддерживает IOCTL; бит 13:1 —
формат блоков IBM, 0—другой формат блоков; бит
11:1 — поддерживает внешние устройства со съемным
носителем, 0 — не поддерживает; бит 6:1 — поддерживает
логические устройства, 0 — не поддерживает; бит 3:1 —
замещает устройство CLOCK5 часов, 0 — не замещает;
бит 2:1 —стандартное устройство NUL, 0— нет; бит 1:
:1 — стандартное выходное устройство, 0 — нет; бит 0:
: 1 — стандартное входное устройство, 0 — нет). Обычно
устанавливается в единицу бит 15 (и, возможно, 14).
В бит 13 записывается единица только для блочных
устройств (а необходимость в них возникает очень редко).
Остальные биты используются для замены драйве-
ров MS-DOS;
3) смещение для части программы, содержащей стра-
тегию размером 2 байта;
4) смещение для части программы, содержащей обра-
ботчик прерывания размером 2 байта;
5) имя устройства размером 8 байт. Оно выравни-
вается по левому краю, а справа при необходимости
дописываются пробелы.
По любому обращению к драйверу ОС сначала вызы-
вает программу стратегии и передает через ES:BX адрес
заголовка запроса — область, через которую осуществ-
ляется обмен информацией между драйвером и вызы-
вающей его программой. Размер заголовка может менять-
ся в зависимости от выполняемых функций ^инициализа-
ция, ввод данных, определение состояния драйвера и т. п.).
Однако первые 13 байт всегда одинаковы и включают
такие сведения (в скобках указан размер поля):
1) длину заголовка запроса (1);
2) код, определяющий номер для блочных устройств
(1);
3) код, содержащий номер последней команды, по-
сланной драйверу (0: инициализация — initialization, 1:
проверка формата диска — media check, 2: создание блока
параметров— build ВРВ, 3: контроль ввода — I/O cont-
136
rol read, 4: ввод данных—read, 5: неразрушающий
ввод— поп-destructive read, 6: статус ввода — input sta-
tus, 7: сброс входного буфера — flush input buffers, 8:
вывод данных — write, 9: вывод с верификацией -
write and verify, 10: статус вывода — output status, 12:
контроль вывода — I/O control write, 13: открыть уст-
ройство— open, 14: закрыть устройство — device close,
15: съемный носитель — removable media, 16: выходной
узел занят — output unit busy, 19: общий запрос IOCTL —
generic IOCTL request, 23: получить логическое устройст-
во — get logical device, 24: установить логическое уст-
ройство— set logical device). Имена команд не имеют
значения, но порядок их расположения друг за другом
важен (1);
4) статус, устанавливаемый каждый раз при вызове
драйвера. Если бит 15 в единице, то в битах 7—0 содер-
жится код ошибки (0— нарушение защиты записи, 1 —
неизвестное устройство, 2 — устройство не готово, 3 —
неизвестная команда, 4 — ошибка проверки по контроль-
ной сумме, 5 — ошибка в длине запроса к устройству,
6 — ошибка поиска, 7 — неизвестный носитель, 8 — сек-
тор не найден, 9 — нет бумаги в принтере, 10 — ошибка
записи, И—ошибка чтения, 12 — общая ошибка, 15 —
неверная замена диска). Бит 8 устанавливается в еди-
ницу при нормальной работе драйвера, бит 9—когда
драйвер занят, биты 10—14 не используются (2);
5) резервную область, используемую MS-DOS (8).
Далее идут данные, необходимые для выполнения
конкретной команды (см. п. 3).
Процедура стратегии сохраняет значение ES.BX
в своих внутренних переменных.
Когда происходит обращение к драйверу, вызывающая
функция ОС помещает код команды в соответствующее
поле заголовка запроса (см. п. 3) . После этого управление
передается обработчику прерываний. В первую очередь
обработчик восстанавливает регистры ES:BX, чтобы они
адресовали заголовок запроса, а затем считывает код
команды (см. п. 3), на основании которого вызывается
нужная процедура, выполняющая команду. После завер-
шения этой процедуры управление возвращается в вызвав-
шую программу. Драйвер может обрабатывать только
некоторые (не все) команды, а для оставшихся осущест-
вляется выход без выполнения каких-либо действий. При
этом в байте статуса устанавливаются в единицу биты
0, 1,8, 15 (см. п. 4).
137
Команда инициализации должна присутствовать во
всех драйверах. Она автоматически выполняется только
при загрузке и обеспечивает начальную установку всех
параметров устройства. Все необходимые действия' в этой
команде определяет пользователь. Однако одно из них
должно быть выполнено обязательно — установка адреса
конца драйвера в четырех байтах, начинающихся со
смещения 14 в заголовке запроса (младшие 2 байта —
смещение и старшие 2 байта — сегмент). Для символь-
ных устройств наиболее важными являются команды вво-
да и вывода. Их заголовок запроса имеет следующую
структуру:
1) рассмотренные выше первые 13 байтов;
2) один байт описания формата диска (только для
блочных устройств);
3) четыре байта со смещением и сегментом буфера
обмена данными;
4) число байтов, которое нужно передать (размером
2 байта);
5) два байта с начальным номером сектора (только
для блочных устройств).
Структуры заголовка запроса для других команд при-
ведены в работе [18].
Перед завершением работы драйвер устанавливает
слово статуса в заголовке запроса.
Если имя драйвера заменяет стандартное устройство
MS-DOS (например, CON, AUX, PRN), работа с соответ-
ствующей программой может осуществляться через пре-
рывания ОС. Номера файлов для стандартных устройств:
О — стандартный вход (stdin), 1 —стандартный выход
(stdout), 2 — стандартный файл для ошибок (stderr),
3 — стандартное последовательное устройство (stdaux),
4—стандартное параллельное устройство (stdprn).
Дополнительные сведения по устанавливаемым драй-
верам устройств и пример их использования'!приведены
в работе [18].
3.8. ДРАЙВЕР ansi.sys.esc-последовдтельности
Драйвер ANSI.SYS — это программа, позволяющая
осуществлять управление клавиатурой и дисплеем на
основе программируемого набора кодов. Она подклю-
чается к ОС через файл конфигурации (CONFIG.SYS)
с помощью команды DEVICE = ANSI.SYS. При необхо-
димости здесь указывается соответствующий путь. В драй-
138
вер посылаются так называемые ESC-последователь-
ности, которые заставляют его реализовать те или иные
операции. ESC-последовательность начинается с символа
ESC. Его ASCII-код равен 27. Для ANSI.SYS в следующем
байте должен идти ASCII-код открывающей квадратной
скобки ([). Далее следуют байты с кодом команды. На-
пример, последовательность из 3 байт: ESC [В — пере-
мещает курсор на строку вниз (здесь В — прописная
буква латинского алфавита). Задать требуемые действия
можно с клавиатуры с помощью команды prompt. На-
пример:
А) prompt $е[7В (ВВОД)
Комбинация из двух символов — $е — соответствует
одному байту ESC, цифра 7 задает количество строк,
на которые перемещается курсор (в нашем примере он
будет перемещен вниз на 7 строк). После выполнения
команды prompt пропадет приглашение ОС (А>). Чтобы
вернуть его, необходимо ввести команду
prompt $п$е(ВВОД)
Символы $n$g можно было поместить и в предыдущую
команду:
А)prompt $e[7B$n$g (ВВОД)
Подобные действия можно выполнять с помощью кон-
струкций языков программирования, например СИ:
printfl "\033[7В")
Укажем теперь команды ANSI-драйвера: ESC [= nh —
установка режима экрана с кодом п (п = 0—40 знаков
в строке, п = 2 — 80 знаков в строке, п = 4 — графический
320X200 точек, п=6 — графический 640X 200 точек);
ESC [п;кН — установка курсора в k-ю позицию п-й строки;
ESC[2J — гашение экрана; ESC[s — запоминание теку-
щей позиции курсора; ESC [и — восстановление запом-
ненной позиции курсора; ESC [nA — сдвиг курсора вверх
на п позиций; ESC [пВ — сдвиг курсора вниз на п
позиций; ESC [nD — сдвиг курсора влево на п пози-
ций; ESC[nC — сдвиг курсора вправо на п позиций;
ESC [nD — управление атрибутами символов (п=0 —
отмена всех атрибутов, п = 1 — выделение яркостью,
п = 4 — подчеркивание, п = 5 — мерцание, п = 7 — инвер-
тирование, п = 8 — исключение видимости); ESC [пт —
управление цветом (п принимает значения 30—37 для цвета
символа и 40—47 для цвета фона: 30, 40 — черный цвет;
139
31,41 — красный; 32,42 — зеленый; 33,43— коричневый;
34,44—синий; 35,45 —фиолетовый; 36,46—голубой;
37,47 — белый); ESC [(расширенный________или___ASCII___код
__клавиши)>; (определение_____клавиши^ р — переназначе-
ние клавиш. Например, команда
л) prompt $n$ g$e [0,59;"Минск"р (ВВОД)
назначает клавише F1 (Ф1) с расширенным кодом 59 стро-
ку "Минск". После нажатия клавиши F1 эта строка будет
появляться на экране дисплея. Команда
А)prompt $n$g$e[65;"dir"; 13 р(ВВОД)
назначает клавише А (прописная латинская буква) с ко-
дом 65 последовательность dir (ВВОД> (13 — ASCII-код
клавиши ВВОД). После нажатия клавиши А будет выво-
диться директорий текущего диска. Команда
А) prompt $n$g$e [0;59;9р (ВВОД)
присваивает клавише F1 код табуляции (9), и она будет
выполнять соответствующие функции.
Следующие два варианта команд позволяют заменить
цифру 0 на цифру 1:
А)prompt $n$g$e[48;49р(ВВОД)
А)prompt $p$g$e["0";"l"p (ВВОД)
Команда
А) prompt $p$g$e [0;60;0;83р (ВВОД)
присваивает F2 код клавиши Del (УДЛ), и она будет
выполнять функции удаления символа.
Еще одна команда ANSI.SYS ESC[6n позволяет счи-
тывать с экрана координаты текущего положения курсора
и выдавать их на стандартное устройство вцрда в виде
строки ESC[Y;XR. Здесь Y — номер строки; X—номер
позиции в строке. Указанную выше последовательность
можно считать из программы на языке СИ в виде строки,
в которой будут содержаться соответствующие коорди-
наты (Y — второй и третий элементы, X — пятый и шестой
элементы). Например, можно написать такую программу:
linclude <stdio.h>
void Min()
[ char str[10];
pnntff \033£6n“);
140
scanf("%s",str); /» строка str будет содерхать после-
довательность ESC£Y;XB »/
prinlf("Us", str); ]
Аналогично все команды для драйвера ANSI могут
быть сформированы в любой прикладной программе.
Достаточно направить соответствующие последователь-
ности на экран дисплея. В заключение заметим, что все
переназначения клавиш действуют только через функции
ОС и не отражаются на прерываниях BIOS.
4. ТЕКСТОВОЙ РЕДАКТОР X-WRITER
4.1. ЗАГРУЗКА И ПОДГОТОВКА К РАБОТЕ
Профессиональный текстовой редактор X-Writer пред-
назначен для подготовки научно-технических документов.
Он выполняет обычные функции редактора, а также имеет
полный набор средств для создания и печати сложных
текстов, включающих специальные символы, формулы,
таблицы, схемы. X-Writer позволяет создавать любое
число надстрочных и подстрочных индексов, составлять
из отдельных элементов сложные символы, включать
в текст иллюстрации и т. д. При подготовке текстового
документа можно использовать до 20 различных шриф-
тов и, кроме того, создавать новые и редактировать имею-
щиеся наборы шрифтов. Редактор удобен тем, что постоян-
но поддерживает на экране изображение текста, пол-
ностью соответствующее выводимому на принтер, что
значительно облегчает набор и исправление сложных
документов. Он исключительно прост в использовании,
имеет логичный набор команд и сдублированное управ-
ление как через систему меню команд, полезную для
начинающих, так и через «быстрые» команды (выполняе-
мые некоторыми комбинациями клавиш), облегчающие
доступ к возможностям системы.
Каталог, в котором размещаются программы для ра-
боты редактора, необходимо сделать текущим в ОС. После
этого для вызова редактора достаточно ввести имя основ-
ного файла (CW.EXE) с помощью команды
ОСУУ(ВВОД)
В командной строке можно указать имя редактируемо-
го файла:
C)CW TEXT (ВВОД)
При запуске редактора производится автоматическая
загрузка файлов конфигурации, драйверов, программ
142
поддержки шрифтов (на экране появляется длинный
список сообщений) и, наконец, с диска считывается файл
документа, если он был указан в командной строке при
вызове. Текст появляется на экране, и можно приступать
к его редактированию. Попытка считывания с диска
несуществующего файла приведет к открытию в редакторе
нового документа, и предоставленный чистый экран можно
использовать для его создания.
Если имя редактируемого файла не было указано,
после загрузки драйверов и шрифтов на экране появ-
ляется входное меню следующего вида:
Please select one of the following commands:
[R] ead a document from dick
[1] mport an ASCII-file from dick
[S] tart a new document
[P] rint a document
[C] hange directory and read document
[Q] uit and return to DOS
Enter command:
Предоставляется возможность выбрать одно из сле-
дующих действий:
R — загрузить файл для редактирования с диска. При
этом на экране высвечивается список имен, но перечисля-
ются здесь далеко не все файлы текущего диска. Считает-
ся, что могут интересовать лишь те, которые имеют стан-
дартно принятое для редактора расширение имени (обыч-
но это .CHI, но оно может быть произвольным и легко
переназначается в редакторе). Это расширение имени,
как правило, присваивается редактируемым файлам по
умолчанию, если не было сделано других назначений.
Перемещением подсвеченной строки можно выбрать необ-
ходимый текстовой файл или в нижней части экрана
набрать любое другое имя. Теперь при нажатии клавиши
ВВОД выбранный файл будет считан с диска, и текст его
становится доступным на экране;
I — считать с диска ASCII-файл. Используя эту ко-
манду, можно загрузить для редактирования обычный
текстовой файл, не содержащий управляющих символов
редактора;
S — открыть новый документ, при этом предвари-
тельно запрашивается имя, которое будет присвоено
соответствующему файлу;
Р — вывести текстовой файл на принтер;
С — выполнить смену текущего директория и загрузить
из него текстовой файл для редактирования;
143
Q— вернуться в среду операционной системы.
Чтобы выполнить любую из перечисленных команд
входного меню, достаточно нажать на клавиатуре клавишу
с соответствующей латинской буквой (напомним соответ-
ствие специальных клавиш русской и латинской клавиату-
ры: УПР —Ctrl; ДОП —Alt; Л — Shift; ВСТ — 5ns;
КЛЮЧ —ESC). “
4.2 ОРГАНИЗАЦИЯ ЭКРАНА РЕДАКТОРА
После успешной загрузки редактора на экране появ-
ляется информация, представленная на рис. 4.1.
TEXT.CHI F2:B0LD__L FULL:10Z DF SYN INS 1ST DOUBL R0W:8 C0L:5 PAC:2
i" г' “ I I I I-----1---1----1----1---1 1 'I
ОКНО РЕДАКТИРОВАНИЯ
MARK LAYOUT SCREEN DELETE READ WRITE PRINT ENVIRON QUIT HELP SPELLCHK
Рис. 4.1. Вид рабочего экрана редактора
В верхней строке содержатся сообщения, характе-
ризующие состояние редактора (режимы редактирования,
положение курсора в тексте, наименование текущего
шрифта ит. п.).
Вторая строка показывает, в каких позициях экрана
установлены метки табуляции. Их положение после за-
грузки зависит от указаний в файле конфигурации, но
может быть легко изменено специальными командами
редактора, которые будут рассмотрены далее.
В нижней части экрана высвечивается список команд
редактора — меню команд.
Остальное поле экрана используется непосредственно
для редактирования текста.
Верхняя строка экрана называется информационной
и содержит следующие сообщения:
1) имя редактируемого файла;
2) наименование текущего шрифта и соответствующей
ему функциональной клавиши;
3) индикатор количества занятой оперативной памяти.
Сообщение FULL: 10 % показывает, сколько места (в %)
редактируемый файл занимает в памяти. Необходимо
следить за показаниями индикатора, и, если количество
144
занятой памяти оказывается более 90 %, рекомендуется
сохранить документ на диске. Иначе, когда объем занятой
памяти достигнет 100 %, редактирование будет прервано;
4) информация о режимах редактирования. Режим
активен, если соответствующее сообщение высвечивается
в верхней строке. Такими сообщениями могут быть:
INS — режим вставки. Если редактор работает в ре-
жиме вставки, набираемые на клавиатуре символы раз-
двигают текст, смещая остаток строки вправо; если ре-
жим выключен, новые символы записываются на место
старого текста. Переключение режима вставки выпол-
няется с помощью клавиши ВСТ;
JST — режим выравнивания. Если режим включен,
строки текста будут автоматически выравниваться по
правой границе листа путем вставки дополнительных
пробелов между словами; если выключен, правая граница
остается невыровненной. Для переключения режима ис-
пользуется комбинация двух клавиш УПР—J;
SYN — режим синхронного набора и редактирования
текста. Если режим включен (в верхней строке отобра-
жается слово SYN), любая команда редактирования
действует на строку по всей ее высоте (т. е. на все индекс-
ные ряды). Добавление символа в строку приводит к син-
хронному сдвигу содержимого всех индексных рядов впра-
во от места вставки, а удаление убирает из строки всю ко-
лонку в позиции удаляемого символа. Этот режим обычно
включают при редактировании текста. При наборе формул,
диаграмм, схем гораздо удобнее переключить редактор
в асинхронный режим, при котором любой ряд строки
можно редактировать независимо. В асинхронном режиме
индикатор SYN в информационной строке погашен, кроме
того, размер курсора уменьшается вдвое. Функции систе-
мы в асинхронном режиме настроены на редактирование
сложных формул, диаграмм, таблиц и т. п. (не действует
автоматический перенос слов, управление курсором изме-
нено, и он ведет себя так, будто каждая строка является
отдельной страницей, а ряды — строками). Переключение
режимов синхронного и асинхронного редактирования
осуществляется нажатием клавиши ПЕЧ/* (в IBM РС/
АТ — Grey* на малой цифровой клавиатуре);
DF — режим набора макропоследовательности. При
его включении все нажатия клавиш сохраняются в созда-
ваемой макропоследовательности символов. Вход и выход
из режима выполняются командой редактора УПР — D;
5) интервал между строками редактируемого текста:
145
SINGLE соответствует интервалу 1 для обычных пишу-
щих машинок; 1'/2 — интервалу 1,5; DOUBLE—2
и TRIPLE - 3;
6) положение курсора в редактируемом тексте, которое
определяется следующими тремя записями:
ROW:30 — указывает номер ряда, в котором нахо-
дится курсор;
COL:50 — номер позиции в строке;
PAG:3— номер текущей страницы.
В нижней части экрана высвечивается перечень всех
имеющихся команд редактора — меню команд. Этот спи-
сок насчитывает 11 основных директив. Обращение к меню
команд и обратный переход к редактированию текста
осуществляются нажатием клавиши КЛЮЧ. Текущая ко-
манда выделяется на экране полосой обратной засветки,
которую можно перемещать по меню влево и вправо нажа-
тием клавиш со стрелками (ч- и ->) или с помощью кла-
виш табуляции.
Выполнить требуемую команду можно несколькими
способами:
1) переместить полосу обратной засветки на нужную
команду и нажать клавишу ВВОД;
2) набрать прописную букву, выделенную в имени
команды. Эти имена подобраны так, чтобы отражать
смысл команды и различаться по первой букве. Если это
не удалось, в качестве прописной выделяется буква
в середине слова (например, footNote);
3) быстрый доступ к любой команде, не требующий
предварительного перехода в командное меню, можно
осуществить непосредственно из режима редактирования
комбинацией клавиши ДОП и прописной буквы в имени
команды.
Каждая команда главного меню имеет подчиненные
команды, которые в свою очередь могут также содержать
набор подкоманд. Таким образом, система сменю имеет
древовидную структуру. Если «пойти» вдоль одной из вет-
вей такого дерева, то через несколько точек ветвления
можно добраться до его листа — т. е. до конкретной
команды. Просмотреть такое дерево без выполнения
команд можно с помощью клавиш со стрелками | и f.
В самой нижней строке экрана при этом расшифровы-
вается назначение каждой текущей команды.
В крайней правой колонке также отображается очень
полезная информация. Подробно о ней будет рассказано
далее.
146
4.3. СТРУКТУРА РЕДАКТИРУЕМОГО ТЕКСТА
Текст документа состоит из последовательности строк,
каждая из которых в свою очередь включает несколько
рядов. Основная часть строки образована двумя рядами,
выше или ниже которых может быть создано любое число
индексных рядов.
При размещении строк в полтора интервала редактор
автоматически вставляет один индексный ряд ниже основ-
ного, при двойном интервале — по ряду сверху и снизу,
при тройном образуются два верхних и два нижних
индексных ряда. При необходимости можно добавить лю-
бое число дополнительных рядов в строку специальными
командами редактора. На экране основной ряд отмечается
символом конца строки в крайней правой позиции, а
индексные ряды — точками. Границы между строками
обозначаются маленькими горизонтальными черточками.
Символы текста имеют высоту, равную двум рядам,
это позволяет размещать индексы с шагом в полвысоты
символа.
Если при наборе текста добавление очередного символа
делает строку слишком длинной, ее последнее слово авто-
матически переносится. В этом случае строка завершается
«мягким концом» в отличие от «жесткого», образуемого
при нажатии клавиши ВВОД. Если включен режим вырав-
нивания (JST), при переносе строка автоматически под-
равнивается под установленную правую границу путем
вставки «мягких» пробелов между словами. Концы строк
и пробелы, вставленные процедурой выравнивания, назы-
ваются «мягкими», поскольку редактор сам при необхо-
димости может перемещать или удалять их. Напротив,
пробелы, вставляемые клавишей пробела, и концы строк,
полученные нажатием клавиши ВВОД, называются «жест-
кими» и не могут автоматически модифицироваться.
Эти ситуации легко различаются на экране. «Мягкие»
пробелы изображаются незаполненным пространством,
а «жесткие» — точкой посредине строки. «Жесткий»
конец строки обозначается закрашенным маркером
в крайней правой колонке экрана, а «мягкий» —
незакрашенным. Метка «жесткого» конца строки рассмат-
ривается как признак конца абзаца.
Редактируемый текст автоматически разбивается на
страницы, размер которых определяется фиксированным
числом рядов (не строк!). При необходимости длина
страницы документа может быть легко изменена. Кроме
147
того, имеется возможность принудительно завершить стра-
ницу в нужном месте или запретить разграничение там,
где это нежелательно.
4.4. КОМАНДЫ ПЕРЕМЕЩЕНИЯ КУРСОРА
В режиме синхронного редактирования текста курсор
перемещается по документу с помощью команд, приве-
денных в табл. 4.1.
Таблица 4.1
Команды, зада-
ваемые комбина-
цией клавиш
Перем еще пие курсора
t й g На позицию вправо
На позицию влево
На позицию вверх
На позицию вниз
На экран вверх
На экран вниз
УПР > На слово вправо
УПР — На слово влево
Гк кон УПР — В начало строки В конец строки В начало документа
УПР — кон В конец документа
Упр — G п В начало страницы с номером п
УПР — Й На верхний индексный ряд
УПР — ф На нижний индексный ряд
В асинхронном режиме клавиши | и f переводят курсор
не на строку, а всего лишь на один ряд вниз и вверх. Пе-
реход с одной строки на другую выполняется клавишами
£ не-
большой интерес представляет возможность быстрого
поиска символов в тексте документа. Эти функции
закреплены за клавишами [-|-] и [ — ] малой цифровой
клавиатуры, которые перемещают курсор на место сле-
дующего или предыдущего вхождения в текст указанного
символа: [ -ф ] задает поиск вперед по тексту от места рас-
положения курсора, а [ — ] — поиск в обратном направ-
лении (от позиции курсора к началу файла). После нажа-
тия клавиши [-ф] или [ — ] вводится символ для поиска.
Например, команда [-ф] А переместит курсор на следую-
щую по тексту букву А. Можно выбрать определенный
шрифт, указав перед искомым символом функциональную
148
клавишу нужного шрифта (например, комбинация
[ — ] F3D задает поиск первой предшествующей буквы D,
набранной шрифтом, соответствующим клавише F3.
Быстрый поиск имеет еще ряд вариантов:
[4~] [-J-] — поиск повторяется по последнему указан-
ному образцу;
[+] ВВОД — курсор переводится в конец абзаца;
[ +j □ — передвигает курсор на следующую страницу;
[ — ] Й— позволяет перейти в первую строку текущей
страницы,
4.5. ВЫБОР ШРИФТА
В редакторе все шрифты связаны с клавишами функ-
циональной клавиатуры. Одновременно можно использо-
вать в тексте до 20 различных шрифтов. Первые 10 разно-
видностей связаны с клавишами Fl,..., F10, оставшимся
соответствуют комбинации Shift — Fl, ..., Shift — F10.
Для переключения надо дважды нажать соответствующую
функциональную клавишу. При этом номер и наименова-
ние текущего шрифта отражаются в информационной
строке редактора. При однократном нажатии клавиш
шрифта набирается только один следующий символ, а те-
кущий шрифт не изменяется.
Как правило, сложно запомнить, какой клавише
соответствует тот или иной знак, особенно это касается
наборов математических, специальных символов, элемен-
тов псевдографики и т. п, В этом случае следует восполь-
зоваться имеющимся режимом подсказки. При одно-
кратном нажатии клавиши шрифта, а затем ДОП—1
(в некоторых версиях ДОП — Н) на экран выводится
изображение клавиатуры, на котором показано размеще-
ние символов данного шрифта. Можно просмотреть
подряд несколько таких схем, переключая их функцио-
нальными клавишами. Кроме того, имеется возможность
прямо по рисунку выбрать нужный знак для вставки
в документ, нажав соответствующую клавишу. После
возврата к режиму редактирования указанный символ
окажется в тексте.
4.6 ОПИСАНИЕ КОМАНД РЕДАКТОРА
В главное меню редактора включены 11 основных
директив. Это команды Mark, Layout, Screen, Delete,
149
Read, Write, Print, Environ, Quit, Help и spellChk. Рас-
смотрим подробнее их назначение и возможности.
Команда Mark содержит набор операций для обработ-
ки целых фрагментов текста. При ее выполнении редактор
переходит в режим отметки фрагмента, когда всякое
передвижение курсора с помощью клавиш со стрелками
выделяет обратной засветкой текст на экране. Управляя
перемещением курсора, можно выделить нужный фрагмент
текста любого размера.' Вывод редактора из этого состоя-
ния осуществляется нажатием клавиши КЛЮЧ. По окон-
чании режима отметки X-Writer не возвращается к обыч-
ному редактированию, а переходит в режим команды
Mark для обработки выделенного фрагмента текста. Об
этом напоминает подчиненное меню, которое появляется
в нижней строке экрана.
Охарактеризуем назначение его подкоманд:
End — выход из режима команды Mark и возврат
к обычному редактированию текста;
Cut — исключение отмеченного фрагмента из доку-
мента. Удаленный текст запоминается в специальном
буфере и может быть воспроизведен затем в любом месте
документа. Для этого предварительно курсор помещается
в нужное место текстового файла. Затем по команде редак-
тора УПР — Р ранее удаленный фрагмент считывается из
буфера и включается в текст, начиная с позиции курсора.
Содержимое буфера сохраняется до следующего приме-
нения команды Cut или Duplicate;
Duplicate — дублирование отмеченного фрагмента
в буфере. Для воспроизведения содержимого буфера
используется та же команда УПР — Р;
Font chg — замена шрифтов в выделенном фрагменте
текста. Единственной командой можно в целом фрагменте
заменить все знаки одного из шрифтов на знаки другого
шрифта с теми же клавиатурными кодами. В ответ на
запросы команды необходимо сначала нажать функцио-
нальную клавишу шрифта, символы которого нужно за-
менить, затем — клавишу шрифта, на символы которого
производится замена. Для замены всех символов фрагмен-
та одним новым шрифтом ответьте на первый запрос
нажатием клавиши ВВОД;
Spac chg — изменение интервала между строками
в выделенном фрагменте текста;
Reformat — переформатирование отмеченного фраг-
мента текста с учетом установленных режимов (границ
полей, интервала между строками, выравнивания). При
150
переформатировании можно сохранить границы абзацев
в отмеченном фрагменте (подкоманда Keep current
paragraphs) либо преобразовать выделенный текст в един-
ственный абзац удалением из него «жестких» концов
строк (подкоманда Format as one paragraph)?
Glue — объединение всех строк выделенного фраг-
мента в одну строку с большим числом индексных рядов.
Это становится гарантией того, что отмеченный фрагмент
всегда будет размещаться на одной странице документа;
Print — вывод отдельного фрагмента текста на прин-
тер;
Help — активизация экрана оперативной подсказки.
Команда Layout содержит следующий набор под-
команд:
Spacing — смена интервала между строками. По под-
сказке команды можно выбрать один из заданных интер-
валов (SINGLE, l'/2, DOUBLE или TRIPLE). Напомним,
что они точно соответствуют стандартным интервалам
пишущей машинки;
Margins — установка границ текста. Применяется для
четырех случаев: Left margin — левое поле; Right mar-
gin — правое поле; Top margin — верхнее поле; Bottom
margin — нижнее поле. Положение левой и правой границ
указывается номером позиции экрана, а высота верхнего
и нижнего отступов определяется количеством рядов.
Левую и правую границу можно установить, не выходя
из режима редактирования. Так как эти команды ис-
пользуются сравнительно часто, для них предусмотрен
быстрый и удобный доступ. Комбинации клавиш УПР— [и
УПР — ] устанавливают в позиции курсора соответст-
венно левую и правую границы текста;
Tabs — установка меток табуляции. Здесь есть свой
набор подкоманд: Set — устанавливает метку табуляции
в текущей позиции курсора (те же действия выполняются
командой УПР — Т); Clear — отменяет метку табуляции
в позиции курсора (для отмены тоже используется ком-
бинация клавиш УПР — Т); Reset to default — восста-
навливает стандартное расположение меток табуляции
(эта информация считывается из файла конфигурации
системы); Delete all — отменяет все метки табуляции
на экране;
Headers — создание и редактирование верхнего заго-
ловка, который представляет собой текст, выводимый при
печати в начале каждой страницы. После набора данной
команды предлагается выбрать тип верхнего заголовка.
151
Дело в том, что в редакторе имеется возможность созда-
вать отдельно заголовок для первой (выбор 1st), второй
(2 nd), третьей (3 rd) и так далее до девятой (9 th) стра-
ниц, а также свой заголовок для четных страниц (выбор
режима Even) и общий заголовок остальных страниц,
для которых не было сделано других определений (De-
fault) . После выбора открывается специальное окно редак-
тирования заголовка, для которого появляется собствен-
ное меню команд. Охарактеризуем некоторые его дирек-
тивы. Набор текста завершается командой Close, закры-
вающей окно и возвращающей курсор к редактированию
основного документа. Команда Delete ликвидирует верх-
ний заголовок страницы. Остальные команды аналогичны
директивам главного меню редактора и имеют такое же
назначение. Новой здесь является лишь команда Insert
counter. Она служит для размещения в тексте заголовка
символа нумерации, который при печати заменяется но-
мером текущей страницы;
Footers — создание и редактирование нижнего заго-
ловка. Действие этой команды аналогично действиям
команды, описанной выше, но связано с редактированием
текста, печатаемого внизу каждой страницы;
Pagination — разделение текста на страницы. Содер-
жит ряд подкоманд. Первая из них — Break page — осу-
ществляет принудительное завершение страницы. Кроме
автоматического разбиения текста самой программой
редактора, можно завершить страницу в любом нужном
месте. По данной команде вводится «жесткий» раздели-
тель страниц непосредственно за строкой, где стоит
курсор. На экране он выглядит сплошной линией попе-
рек текста (в отличие от шриховой линии при автомати-
ческом разделении). Его можно удалить, повторив ту же
команду. Для удобства эта директива продублирована
комбинацией клавиш УПР — В. Вторая подкоманда —
Inhibit page — запрещает окончание страницы в позиции
курсора (УПР — I). Применяется в том месте, где смена
страниц нежелательна, и гарантирует, что конец страницы
будет размещаться либо выше, либо ниже отмеченной стро-
ки. Отменить пометку можно повтором команды. Третья
подкоманда — Remove break — удаляет «жесткий» конец
страницы и разрешает размещение на его месте автома-
тического разделителя. Четвертая подкоманда — Font for
page numbers — осуществляет установку шрифта, кото-
рым будут печататься номера страниц. В ответ на ее
запрос надо нажать клавишу шрифта или клавишу
152
ВВОД—для подавления нумерации. Последняя под-
команда — Paper length — устанавливает размер стра-
ницы. Следует обратить внимание на то, что длина стра-
ницы задается количеством рядов, а не строк. Напомним,
что в строке текста, набранного в один интервал пишущей
машинки, содержится два ряда, в полтора интервала —
три ряда, в два интервала — четыре и в три интервала —
шесть рядов. Кроме основного текста, в длину страницы
включаются ряды, отведенные для верхнего и нижнего
полей, заголовки страницы, а также сноски (рис. 4.2).
НАЧАЛЬНАЯ ПОЗИЦИЯ ГОЛОВКИ
ПЕЧАТАЮЩЕГО УСТРОЙСТВА
ВЕРХНЕЕ ПОЛЕ
ВЕРХНИЙ ЗАГОЛОВОК СТРАНИЦЫ
ОСНОВНОЙ ТЕКСТ
ОПРЕДЕЛИТЕЛЬ СНОСОК
ТЕКСТ СНОСОК
НИЖНИЙ ЗАГОЛОВОК СТРАНИЦЫ
НИЖНЕЕ ПОЛЕ
ОТСТУП ОТ КРАЯ
ЛИСТА ПРИ ПЕЧАТИ
(MARGIN OFFSET)
Рис. 4.2. Организация страницы экрана
Общее число рядов на странице при редактировании
сохраняется постоянным;
foot Notes — установка параметров для организации
сносок в тексте. Здесь есть подкоманды: Font for footnote
numbers — указание шрифта для печати номеров сносок
(в ответ на запрос команды надо нажать клавишу шрифта
или клавишу ВВОД — для подавления печати номеров
сносок); Separator — создание и редактирование текста,
отделяющего сноски от основного документа (печа-
тается на каждой странице, где имеются сноски); Endno-
153
tes — установка режима, при котором все сноски печа-
таются в конце документа; Graphics — указание файла
с графической информацией для включения его при печати
в текст документа.
В директиве Screen объединены наиболее часто ис-
пользуемые команды редактирования. Именно поэтому все
они выполняются не только выбором через систему меню,
но и с помощью простых комбинаций клавиш, облегчаю-
щих их вызов. К ним относятся:
Paste (УПР — Р) — воспроизведение содержимого бу-
фера в том месте документа, где установлен курсор;
Format (УПР — F) — переформатирование текста от
позиции курсора до конца абзаца с учетом предварительно
установленных режимов;
Search (УПР — S) —поиск указанного фрагмента
текста. Команда запрашивает образец для поиска, а затем
ищет первое вхождение его в текст документа. Направле-
ние поиска устанавливается вперед по тексту, т. е. от
места расположения курсора к концу файла. Образец
текста для поиска набирается всегда с учетом необходи-
мых шрифтов. В синхронном режиме поиск производится
только в базовых рядах строк, при включении асинхрон-
ного режима будут просматриваться и все индексные
ряды. При успешном завершении поиска курсор пере-
мещается в начало искомого фрагмента, в противном
случае он остается на месте;
Replace (УПР—R)—поиск указанного фрагмента
текста и замена его новым набором символом (поиск
ведется по правилам предыдущей команды). Запросив
образец для поиска и образец для замены, команда тре-
бует подтверждения выполнения. Это требование появ-
ляется в виде дополнительного меню, содержащего че-
тыре подкоманды: Yes — выполняется замена найден-
ного фрагмента текста новым фрагментом и начинается
поиск следующего вхождения искомого образца; No —
замена не производится, но поиск продолжается; Glo-
bal — замена выполняется по всему тексту без дополни-
тельного подтверждения; Cancel — прекращение поиска;
Last srch (УПР — L) — повтор последней введенной
команы поиска или замены;
FootNote (УПР—N) —создание и редактирование
сносок в тексте. В позиции курсора основного документа
появляется специальный символ сноски и открывается
дополнительное окно для ее редактирования со своим ме-
ню команд. Такой же символ заносится в первую позицию
154
окна редактирования сноски. Можно вставить его в любое
другое место текста сноски, для этого в меню имеется
команда Insert counter. При выводе документа на принтер
эти символы заменяются порядковым номером сноски.
Чтобы отредактировать ранее созданную сноску, необхо-
димо в тексте документа переместить курсор на соответ-
ствующий символ и после этого применить данную ко-
манду (УПР — N). Текст нужной сноски будет воспроиз-
веден в открывшемся дополнительном окне. Для завер-
шения редактирования сноски и перехода к основному
тексту используется команда Close. Заметим, что инст-
рукция появившегося меню Delete удаляет лишь текст
в дополнительном окне, сохраняя наличие сноски. Ненуж-
ная сноска будет ликвидирована только при удалении
из текста документа соответствующего символа сноски.
В один документ можно ввести не более 90 сносок;
Open — переход к редактированию дополнительного
документа. Наряду с текстом основного документа имеет-
ся возможность одновременно работать еще с одним. Он
помещается в специально отведенное окно, которое появ-
ляется на экране по команде Open. Возврат к основному
тексту реализуется командой Close. Удобным является
то, что для обоих документов используется один общий
буфер. Его содержимое сохраняется при переходе от од-
ного окна редактирования к другому, что позволяет легко
переносить фрагменты текста между двумя документами.
Дополнительное окно редактирования имеет и много дру-
гих применений.
More...— другие возможности команды Screen, к ко-
торым относятся: Center (УПР — С) —центрирование
текущей строки; Move rgt (УПР— М) — смещение теку-
щей строки к правой границе текста; Add (УПР — А) —
добавление пустого индексного ряда ниже того, в котором
находится курсор.
Подкоманды директивы Delete выполняют следующие
действия:
Word (УПР — W) — удаление слова, на которое ука-
зывает курсор;
Row (УПР — Z) — удаление индексного ряда, в ко-
тором установлен курсор;
Lime (УПР----<-) — удаление строки текста в позиции
курсора;
Document — удаление из памяти основного документа
и создание нового (при этом запрашивается имя, которое
будет присвоено новому текстовому файлу);
155
Header — удаление верхнего заголовка страницы;
Footer — удаление нижнего заголовка страницы;
Separator — удаление разделителя, печатаемого на
странице между основным документом и текстом сно-
сок;
Notepad — удаление из памяти дополнйтельного доку-
мента.
Команда Read позволяет перейти к выполнению сле-
дующих подкоманд:
new Document — удаление из памяти текущего доку-
мента и считывание на его место с диска текста нового
документа;
Merge document—вставка содержимого считанного
с диска файла в текст основного документа, начиная
с места, определенного позицией курсора;
Import ASCII — загрузка для редактирования обыч-
ного ASCII-файла. Это позволяет использовать X-Writer
для работы с текстовыми файлами, не содержащими
управляющих последовательностей редактора. Однако
если ASCII-файл включает русский текст или другие
символы с кодами, превышающими 127, эту команду
использовать нельзя. Для приведения ASCII-файла к фор-
мату редактора выгоднее воспользоваться специальной
утилитой TCW, которая перекодирует любой ASCII-файл,
правильно переводя его символы в шрифты редактора
X-Writer, формируя строки с необходимым интервалом.
Все параметры перекодировки запрашиваются в процессе
работы самой утилиты;
Notepad — считывание с диска и загрузка для редак-
тирования дополнительного документа.
Директива Write содержит такой набор подкоманд:
Document — сохранение основного документа на диске
в виде файла, которому присваивается текущее имя,
установленное в редакторе. Одновременно создается копия
файла (с расширением имени ВАК), которая будет хра-
нить предыдущий вариант документа:
Export ASCII — сохранение текста документа в виде
ASCII-файла (без управляющих последовательностей,
информации о шрифтах и т. п.). Используется при редак-
тировании обычных текстовых файлов;
Change name — изменение имени текущего документа.
Следствием выполнения команды является только замена
имени текстового файла, запись на диск при этом не
производится;
Set extension — назначение расширения имени, кото-
156
рое будет присваиваться редактируемым файлам по умол-
чанию;
Backup frequency—задается периодичность автома-
тического сохранения редактируемого файла на диск.
Промежуток времени, через который запись текста повто-
ряется, указывается в минутах. Отключить автомати-
ческую запись можно, установив очень большой период
сохранения, скажем 9999 минут;
Notepad — запись на диск дополнительного документа.
В отличие от команды Write Document здесь при каждой
записи будет запрашиваться имя файла для сохранения.
Команда Print используется для печати документа.
Чтобы осуществить это, необходимо установить требуемые
параметры печати и выполнить команду Go. Приостано-
вить печать можно в любой момент нажатием произволь-
ной клавиши. Перед тем как напечатать первый документ,
редактор загружает и представляет во внутренней форме
соответствующий набор шрифтов. При печати последую-
щих документов подгружаются лишь недостающие шриф-
ты. Print имеет следующие подкоманды:
Go— начало печати;
Pitch — выбор шрифта для печати: пропорциональный
шрифт (Proportional) или шрифт с равной шириной
букв— Pica (10 символов на дюйм) и Elite (12 символов
на дюйм);
Quality — выбор режима печати: Draft — черновико-
вый режим; Enchanced—улучшенный; Letter quality —
качественный;
Options — установка параметров печати: From/to pa-
ge— указание интервала страниц для вывода на печать;
Stop between pages — установка или отмена режима
приостановки печати перед каждой новой страницей;
Margin offset — изменение величины левого отступа от
края листа при выводе на печать; Copies — задание
числа копий для печати документа; Port — указание
порта, к которому подключен принтер со следующими
возможными значениями — LPT1, LPT2, LPT3, СОМ1,
COM2, COM3, PRN, AUX (если неизвестно, каким образом
подключен принтер, следует установить PRN);
Numbering — установка начальных номеров: First
page number — для нумерации страниц и footNote
number — для нумерации сносок;
From file — печать документа из указанного файла.
Как правило, шрифты принтера при загрузке требуют
большого объема памяти. Если документ и шрифты одно-
157
временно не помещаются в оперативной памяти, можно
печатать текст непосредственно из файла на диске.
В таком режиме страницы текста считываются в память
по одной, а редактор удаляет основной и дополнительный
документы и содержимое буфера для освобождения па-
мяти;
То file — запись совокупности кодов, посылаемых на
принтер при печати, в файл на диске.
Команда Environ используется для установки пара-
метров рабочей среды редактора и включает следующие
подкоманды:
Disk — выполнение операций с диском: Display direc-
tory — просмотр указанного директория; Change direc-
tory — смена текущего директория; Erase file — удаление
файла с текущего диска;
Font — подключение необходимого набора шрифтов:
List — вывод на экран списка шрифтов, используемых
редактором с указанием их привязки к функциональным
клавишам; Read — считывание с диска и подключение
нового шрифта (в процессе выполнения команды необхо-
димо указать функциональную клавишу, которой будет
поставлен в соответствие загружаемый шрифт); Delete —
удаление из памяти указанного шрифта;
Keu sequence — обработка макропоследовательностей
символов; Define key sequences (УПР — D) —создание
макропоследовательности. По этой команде редактор пере-
ходит в режим, когда любое нажатие клавиши запо-
минается в макропоследовательности символов. Предва-
рительно запрашивается имя для создаваемой макро-
последовательности. Оно может содержать до 60 симво-
лов, 10 из которых являются значащими. Макропосле-
довательности, которые предполагается использовать
наиболее часто, удобно связать с комбинациями ДОП —
клавиша для более простого обращения к ним. Набор
макропоследовательности завершается командой УПР —
D. Макропоследовательность может содержать не более
75 символов; Key sequences replay—воспроизведение
макропоследовательности по ее имени. Те же действия
выполняет комбинация УПР — К; List — вывод на экран
текущего списка доступных макропоследовательностей;
Write — запись набора макропоследовательностей в файл
на диске для последующего использования; Read —
загрузка макропоследовательностей, определенных в
файле;
Modes — переключение режимов редактора: Insert —
158
режим вставки; Synch mode — режим синхронного набора
и редактирования текста; Justification mode — режим
выравнивания; Menu line — установка режима, когда
меню команд постоянно высвечивается в нижней части
экрана (подкоманда Display) либо производится удаление
командной строки для увеличения рабочего поля при
редактировании текста (подкоманда Hide). В последнем
случае меню команд появляется только при непосредст-
венном обращении к нему;
Configuration — конфигурирование системы: List —
вывод на экран информации о текущей конфигурации;
Save — сохранение текущей конфигурации в файле на
диске; Read — считывание новой конфигурации из файла
и установка соответствующих параметров системы.
По команде Help на экран дисплея выводится крат-
кая информация о возможных командах редактора (см.
табл. 4.2).
Таблица 4.2
Команда
УПР — А
УПР — В
УПР — С
УПР — D
УПР — F
УПР — G п
УПР — I
УПР — J
УПР — К
УПР — 1.
УПР — М
УПР — N
УПР — Р
УПР — R
УПР — S
УПР — Т
УПР — W
УПР — Z
УПР — [
УПР — ]
Выполняемое действие
Добавление индексного ряда в позиции курсора
Установка и удаление принудительного конца стра-
ницы
Центрирование текущей строки
Создание макропоследовательности
Переформатирование текста до конца страницы
Перемещение курсора в начало страницы с номе-
ром п
Запрещение смены страниц в позиции курсора
Включение/выключение режима выравнивания
Воспроизведение макропоследовательности по имени
Повтор последней команды поиска
Смещение текущей строки к правой границе текста
Создание или редактирование сноски
Воспроизведение содержимого буфера
Поиск и замена последовательности символов
в тексте
Поиск последовательности символов в тексте
Установка/отмена метки табуляции в позиции кур-
сора
Удаление слова, на которое указывает курсор
Удаление подстроки
Установка левой границы текста в позиции курсора
Установка правой границы текста в позиции кур-
сора
159
Команда Quit обеспечивает выход в среду ОС.
Команда spellChk предоставляет средства граммати-
ческого анализа написания слов. Необходимая проверка
осуществляется путем сравнения с образцами, хранящи-
мися в словаре. Для каждого текстового документа
может быть создан словарь допустимых слов. Он поме-
щается в файл, имя которого совпадает с именем основ-
ного документа, а тип — обычно АУХ (от слова auxila-
ry— дополнительно). В процессе грамматического ана-
лиза производится обращение как к основному, так и к
дополнительному словарю и, кроме того, к любому
словарю, который был предварительно загружен в память
командой spellChk Read. Команда главного меню spellChk
имеет две подкоманды: Read — выполняется загрузка
в память любого дополнительного словаря, имеющегося
на диске; Check spelling — запускается программа про-
верки правильности написания слов. Просмотр текста
начинается с места расположения курсора в направлении
к концу документа. При обнаружении в тексте «подозри-
тельного» слова могут возникнуть две ситуации: 1) на
экране может появиться сообщение No Guess, которое
означает, что в словаре подобного шаблона не существует,
и в результате трудно сделать вывод о правильности
написания; 2) для найденного слова в словаре могут су-
ществовать сходные образцы, но ни с одним из них оно не
совпадает; при этом на экране появятся все варианты
подобных слов. В обоих случаях оценка ситуации и при-
нятие решения возлагаются на человека. Ему предостав-
ляются следующие возможности дальнейших действий:
заменить найденное слово одним из предложенных, что
осуществляется после перемещения на нужное слово
подсвеченной строки и нажатия клавиши ВВОД; Igno-
re — игнорировать данное предупреждение, но только
в этом конкретном случае; Acceprt — разрешить появле-
ние такого слова в тексте (хотя его нед в словаре)
и не предупреждать об этом повторно; Write — записать
найденное слово в дополнительный словарь; Cansel —
завершить проверку.
5. АЛГОРИТМИЧЕСКИЙ ЯЗЫК ПАСКАЛЬ
5.1. ПРОГРАММЫ И ДАННЫЕ
Структура ПАСКАЛЬ-программы приведена на рис.
5.1. Первая строка (блок /) состоит из зарезервирован-
ного слова PROGRAM — имени программы, которое зада-
5 ТЕЛО
ПРОГРАММЫ
6 END.
Рис. 5.1. Структура программы на языке ПАСКАЛЬ
ется программистом и заканчивается точкой с запятой,
используемой для разделения инструкций языка. Сразу
же после имени могут следовать параметры программы.
Далее (блок 2) идут строки с объявлениями данных
(о них речь пойдет несколько позже). В блоке <? описы-
ваются процедуры и (или) функции. Такими терминами
в ПАСКАЛе именуют различные подпрограммы. Блок 4
содержит зарезервированное слово BEGIN (без точки
с запятой после него), открывающее тело программы.
6 Скляров В. А. 161
Тело-программы (блок 5) содержит инструкции обработки,
т. е. команды, последовательное выполнение которых
позволяет реализовать заданный алгоритм. Последняя
строка программы (блок 6) содержит зарезервированное
слово END с точкой (END).
При написании инструкций ПАСКАЛя используются
определенные символы, составляющие алфавит языка,
который включает латинские прописные и строчные буквы,
цифры и специальные знаки. К последним обычно отно-
сятся: . (точка),, (запятая),’ (апостроф), ; (точка с за-
пятой), : (двоеточие), ф (номер), — (пробел), * (звез-
дочка), + (плюс), / (дробная черта), — (минус), л
(стрелка вверх), = (равно), '> (больше), <_ (меньше),
$ (знак денежной единицы), ( ) (скобки круглые), [ ]
(скобки квадратные), { } (скобки фигурные), ___ (под-
черкивание). Специальные знаки (каждый в отдельности
либо в комбинации друг с другом) позволяют задавать
операторы и знаки операций, среди которых наиболее
часто используются следующие:
1) : = (два символа —двоеточие и равно — опера-
тор присваивания; например, если А и В — переменные,
то запись А: = В говорит о том, что переменной А при-
сваивается значение переменной В);
2) + (знак операции сложения; если А, В и С пере-
менные, то допустима инструкция А: = В-{-С);
3) * (знак операции умножения; допустима инструк-
ция А: = В*С);
4) — (знак операции вычитания; например, А: =
= В— С);
5) / (знак операции деления; например, А: = В/С);
6) .. (два символа — точка и точка — знак диапазона
значений;.например, запись А=1..1О говорит о том, что
переменная А может принимать одно из значений 1, 2,
3, 4, 5, 6, 7, 8, 9, 10; заметим, что здесь используется знак
равенства, а не оператор присваивания); „
7. (,), =,) = , (=, ( ) (знаки операций отношения:
< — меньше, ) — больше, = — равно, ) = — больше или
равно, <= — меньше или равно, ( ) — не равно; напри-
мер, истинны записи 3)2, 4( >5, 2 <=2);
8) (**),{ ) (совокупность знаков, используемых для
записи комментариев; например, правильными и эквива-
лентными являются две следующие записи: (*город
Минск*), {город Минск));
9) ; (символ, используемый для разделения инструк-
ций языка);
162
10) . (символ, стоящий после последнего слова END
в конце программы);
11) ’ (знак, используемый для вывода символьной
информации на экран дисплея либо на принтер; если в
процедуре вывода последовательность символов заклю-
чить в апострофы, например ’город Минск’, то она без
изменений будет выведена на экран дисплея либо на
принтер; этот же знак используется и в некоторых других
инструкциях, о чем будет сказано далее).
Важным понятием языка является идентификатор, ко-
торый используется для наименования различных объек-,
тов (имени программы, переменных, констант и т. п.).
Идентификатор может включать латинские буквы, цифры
и символ подчеркивания, причем первым символом не
должна быть цифра. Длина идентификатора ограниченна
и определяется характеристиками соответствующего тран-
слятора. В ПАСКАЛе обычно не различаются строчные
и прописные буквы, поэтому идентификаторы PROG и prog
будут именовать один и тот же объект.
Язык дает возможность использовать следующие типы
данных.
1. INTEGER (целый)—задает значения, к которым
относятся все целые числа, например —5, 0, 64 и т. п. Для
16-разрядных ПЭВМ диапазон возможных целых значе-
ний находится в пределах от —32768 до 32767. В ПАС-
КАЛе определена стандартная константа MAXINT =
= 32767.
2. REAL (вещественный) — задает числа, которые мо-
гут иметь дробную часть, отделяемую точкой, например
—3.14, 0.0, 38.16 и т. п. Вещественные числа могут быть
записаны также в форме с плавающей точкой, например
—2.16Е-|-4 (что равно —2.16Х 104). Число перед сим-
волом Е называется мантиссой, а после символа Е — по-
рядком.
3. BOOLEAN (логический) — определяет два значе-
ния, которые выражаются зарезервированными словами
TRUE (истина) и FALSE (ложь).
4. CHAR (символьный) — описывает значения, кото-
рыми являются символы, т. е. цифры, буквы и специаль-
ные знаки, например F, 8, /, # ит. п. Константы символь-
ного типа при употреблении заключаются в апострофы,
например ’F’, ’8’ и т. п.
5. SHORT1NT (короткий целый) — задает целые чис-
ла, имеющие длину один байт и лежащие в диапазоне
от — 128 до 127.
163
6. BYTE (байт) — описывает неотрицательные целые
числа, имеющие длину один байт и лежащие в диапазоне
от 0 до 255.
7. WORD (слово) — задает неотрицательные целые
числа, имеющие длину одно слово (для 16-разрядных
ПЭВМ — два байта) и лежащие в диапазоне от 0 до
65535.
8. LONGINT (длинный целый) — определяет целые
числа, имеющие длину четыре байта и лежащие в диа-
пазоне от —2147483648 до 2147483647.
9. POINTER (указатель) — задает числа, являющие-
ся указателями, т. е. адресами объектов в оперативной
памяти ПЭВМ. Для хранения значения типа POINTER
отводится четыре байта.
Заметим, что конкретный транслятор может допускать
возможность использования не всех перечисленных типов.
Кроме указанных выше, в ПАСКАЛе существуют
перечисляемые и интервальные типы. Для их задания
применяется зарезервированное слово ТУРЕ (тип). Пред-
положим, что идентификатор SEASONS может принимать
одно из четырех значений: SPRING, SUMMER, AUTUMN,
WINTER. Тогда можно записать следующее объявление:
TYPE SEASONS = (SPRING, SUMMER, AUTUMN, WINTER);
Введенный тип называют перечисляемым, поскольку
необходимо перечислить все принадлежащие ему значе-
ния. В ПАСКАЛе можно объявить новый тип данных,
который будет частью уже существующего типа, на-
пример:
TYPE MONTHLY= 1..12;
LETTERS = 'A’..’Z’;
Значения, входящие в состав основных типов данных,
упорядочены. Например, 127 0 101, 0> —3 и т. п. Чаще
всего ’A’<’B’<...<’Z’, ’0’<’1’<...<’9’, FALSE<TRUE.
Естественным образом упорядочены значений; составляю-
щие перечисляемые типы данных, например для приве-
денного выше объявления SPRING < SUMMER < AU-
TUMN <_ WINTER. Поэтому для задания интервала
(в интервальном типе), являющегося частью последо-
вательности значений, образующих эти типы, достаточно
указать его верхнюю и нижнюю границы. Исключением
является тип REAL: не разрешается задавать интервалы
относящихся к нему значений.
В ПАСКАЛе при объявлении данных (см. рис. 5 1)
наиболее часто применяется следующий порядок:
164
1) с использованием зарезервированного слова LABEL
описываются метки, встречающиеся в теле программы
(о них мы будем говорить позже при рассмотрении опера-
торов безусловного перехода);
2) с использованием зарезервированного слова
CONST описываются константы (в языке определены
стандартные константы MAXINT= 32767, Р1= 3.1415...,
TRUE и FALSE);
3) с использованием зарезервированного слова ТУРЕ
описываются типы данных;
4) с использованием зарезервированного слова VAR
описываются переменные;
5) с использованием зарезервированных слов PROCE-
DURE и FUNCTION описываются процедуры и функции
(о них мы будем тоже говорить позже).
При объявлении данных могут выбираться лишь неко-
торые пункты из перечисленных. Блок 2 (см. рис. 5.1)
может вообще отсутствовать для тривиальных программ.
Текст в строке программы может начинаться с любой
позиции, благодаря чему имеется возможность наглядно
выделять некоторые группы записей и повышать удобство
чтения. В объявлениях данных везде употребляется
знак (=) — равно, а не оператор присваивания, каждое
объявление заканчивается точкой с запятой (;), тип пере-
менной задается после символа двоеточие (:). Транслятор
в процессе компиляции обычно проверяет принадлеж-
ность идентификатора допустимому типу, и, если она
нарушается, выдается сообщение об ошибке.
Для большинства трансляторов в идентификаторах
нельзя использовать русские буквы. Это ограничение не
распространяется на комментарии и значения строковых
констант (типа ’МИНСК’).
5.2. ВВОД И ВЫВОД
В ПАСКАЛе предусмотрены четыре стандартные про-
цедуры ввода-вывода: READ (читать данные), READLN
(читать данные с переводом строки), WRITE (выводить
данные), WRITELN (выводить данные с переводом
строки).
Процедуры ввода записываются в следующем виде:
READ (список переменных);
READLN (список переменных);
Элементы списка отделяются друг от друга запятыми.
Получив инструкцию READ или READLN, ПЭВМ при-
165
останавливает работу и ждет, когда пользователь введет
с терминала значения, которые будут по очереди при-
сваиваться переменным, стоящим в списке ввода. Когда
все переменные примут определенные пользователем зна-
чения, выполнение программы будет продолжено с
инструкции, следующей за READ. Процедура READLN
аналогична READ, за исключением того, что после ввода
всех значений она переводит курсор в начало следующей
строки экрана.
Для правильного ввода данных необходимо выполнять
следующие правила:
1) вводимые числовые значения разделяются про-
белами;
2) символьные данные при вводе не заключаются
в апострофы;
3) тип вводимых данных должен соответствовать типу
переменных, указанных в списке процедуры READ или
READLN;
4) с помощью процедур READ и READLN можно
вводить только значения простых стандартных типов
(за исключением BOOLEAN и POINTER), а также типа
STRING— строка символов.
Процедуры вывода записываются в следующем виде:
WRITE (список вывода);
WR1TELN (список вывода);
В списке вывода можно задавать через запятую кон-
станты, переменные выражения, функции, строки симво-
лов. Процедура WRITE (WRITELN) вычисляет их зна-
чения и выводит на экран дисплея.
Для каждого объекта вывода может указываться
формат. Для этого после очередного элемента списка за-
писываются двоеточие и константа (переменная, выра-
жение) целого типа, которая указывает ширину поля
вывода. Например:
WRITE (’M1NSK’:1O,A:7);
Здесь для записи строки МИНСК отводится 10 позиций
экрана, а переменной А — 7 позиций. Если длина выво-
димого значения меньше ширины поля вывода, это зна-
чение сдвигается к правой границе поля, а левая часть
заполняется пробелами. Если окажется, что поле, отве-
денное для записи объекта вывода, короче, чем требуется,
заданный формат игнорируется, и для вывода объекта
будет отведено минимально необходимое число позиций.
166
Для объектов вещественного типа требуется допол-
нительно определить размер поля, выделяемого для записи
дробной части числа. Для этого после первого указателя
формата, характеризующего общую ширину поля, через
двоеточие записывается целая константа (переменная,
выражение), задающая число позиций для представ-
ления дробной части выводимого значения. Например:
WRITE (А/В: 7:2);
Здесь 7 — общее число позиций для вывода веществен-
ного значения (включающее и позицию для изображения
десятичной точки); 2 — число цифр в дробной части (по-
сле десятичной точки). Если для вывода вещественного
значения используется формат, в котором задана только
ширина поля вывода, на устройстве вывода число появит-
ся в форме с плавающей точкой.
Процедура WRITELN в отличие от WRITE после вы-
вода данных переводит курсор на новую строку экрана.
Транслятор ПАСКАЛя предполагает ввод данных со
стандартного устройства ввода (с клавиатуры) и их
вывод на стандартное устройство вывода (экран дисплея).
Для вывода данных на принтер необходимо в качестве
первого аргумента процедур WRITE (WRITELN) ука-
зать имя LST. Например:
WRITE (LST, ’МРТИ’);
Здесь на принтер будет выведена строка МРТИ.
Процедуры READLN и WRITELN можно использовать
и без аргументов. Процедура READLN позволяет про-
пустить оставшуюся часть текущей входной строки, про-
цедура WRITELN используется для того, чтобы про-
должить размещение последующих данных на новой
строке.
5.3. ОПЕРАТОРЫ И ВЫРАЖЕНИЯ
Выражения представляют собой формулы для вычис-
ления значений. Они состоят из операндов (переменные,
константы и др.) и операторов (сложение, вычитание,
умножение и др.). Порядок выполнения операторов при
вычислении значения выражения определяется их при-
оритетами и может регулироваться с помощью скобок.
Операторы делятся на следующие группы (ниже они
перечислены в порядке убывания приоритетов их вы-
полнения) :
167
1) изменения знака (например, А.:— — В;);
2) логического отрицания (как правило, они приме-
нимы лишь к логическим переменным и определяются
зарезервированным словом NOT, например А: = NOT В;);
3) типа умножения;
4) типа сложения;
5) отношения.
Операторы с более высоким приоритетом выполняются
раньше операторов, приоритет которых ниже. Если при-
оритет одинаков, то раньше выполняется тот оператор,
который стоит левее.
Основные операторы типа умножения сведены в
табл. 5.1. Символом ,_, помечены обязательные пробелы,
Таблица 5.1
Знак опера- тора Оператор Тип операн- да 1 (В) Тип операн- да 2 (С) Тип резуль- тата (А) Пример
1 2 3 4 5 6
* Умно- Целый Целый Целый А: = В*С;
жение
* Умно- жение Целый или веще- ственный Вещест- венный Вещест- венный А: =В*С;
/ Деление Целый или веще- ственный Целый или веще- ственный Вещест- венный А: = В/С;
D1V Цело- численное деление Целый Целый Целый A: = Bl_,DJVl_,C;
MOD Деление по моду- лю Целый Целый Целый A: = B^MOD^C
AND Логиче- ская конъ- юнкция Логиче- ский Логиче- ский Логиче- ский A; = B^AND^C;
SHL Сдвиг влево Целый Целый Целый A: = B^SHL^C;
SHR Сдвиг вправо Цел ы й Целый Целый А: = Bi_< SHR i_iC;
которые не имеют явного графического изображения.
Поясним оператор SHL. Если записано 5 SHL 2, то число
5, стоящее слева, переводится в двоичный код. Этот код
сдвигается влево на 2 разряда (2 соответствует числу
справа от SHL), и результат представляется в десятич-
168
ном коде (полученный результат будет 20). Для оператора
SHR производятся те же действия, но сдвиг выполняется
вправо.
Основные операторы типа сложения сведены в
табл. 5.2.
Таблица 52
Знак опера- тора Оператор Тип операнда 1 (В) Тип операнда 2 (С) Тип резуль- тата (А) Пример
Сложение Целый Цел ы й Целый А: = В + С
+ Сложение Целый или вещест- венный Вещест- венный Вещест- венный А: = В + С
— Вычита- ние Цел ы й Целый Целый А: = В —С
— Вычита- ние Целый или вещест- венный Вещест- венный Вещест- венный А: = В —С
OR Логиче- ская дизъ- юнкция Логиче- ский Логиче- ский Логиче- ский А: = Вь_, OR^C;
XOR Исключа- ющая логи- ческая дизъюнкция Логиче- ский Логиче- ский Логиче- ский А:=В^ XOR^C,
Оператор XOR можно представить через операторы
AND, OR и NOT : В XOR С — это то же самое, что и В
AND NOT С OR NOT В AND С.
Заметим, что в некоторых версиях языка ПАСКАЛЬ
разрешается использовать логические операции и в выра-
жениях с целыми переменными. В этом случае значения
операндов, участвующих в операции, преобразуются из
десятичной формы в двоичную. Операторы AND, OR, XOR
выполняют операции над двоичными эквивалентами со-
ответствующих десятичных операндов, и результат пре-
образуется в десятичную форму. Например, если А = 6,
В = 3, то A AND В=2 (110 Д 011 = 010), A OR В=7
(110V011= 111), A XOR В = 5 (110ф011= 101).
Операторы отношения были описаны в § 5.1.
Для организации циклического повторения вычислений
в языке ПАСКАЛЬ предусмотрены три оператора: FOR,
WHILE и REPEAT. Запись инструкций с оператором
FOR представляется в следующих двух формах:
1) FOR переменная: = выражение 1 ТО выражение 2 DO инструк-
ция или блок;
169
2) FOR переменная: = выражение 1 DOWNTO выражение 2 DO
инструкция или блок;
Значения выражений 1 и 2 — целые. Для первой фор-
мы следует выполнять условие «выражение 1»<«вы-
ражение 2», для второй — «выражение 2»<«выражение
1». Переменная, стоящая за словом FOR, обычно назы-
вается управляющей. В языке ПАСКАЛЬ принято сле-
дующее правило: любая группа инструкций, размещае-
мая между зарезервированными словами BEGIN и END
(после END ставится точка с запятой), рассматривается
как одна. Слова BEGIN и END иногда называют опера-
торными скобками, так как их используют для объеди-
нения нескольких инструкций в один блок. Инструкция
(блок), следующая за словом DO, является телом цикла.
Первую форму можно прочитать так: для переменной,
последовательно принимающей через единицу значения,
возрастающие от значения выражения 1 до (ТО) значе-
ния выражения 2, выполнять (DO) инструкцию или блок.
Например, при выполнении инструкции
FOR I: = 1 ТО 3 DO WRITELN(’l = ’, 1:1);
на экран дисплея будут выведены три строки:
1= 1
1= 2
1 = 3
Вторую форму можно прочитать так: для переменной,
последовательно принимающей через единицу значения,
убывающие от значения выражения 1 до (DOWNTO)
значения выражения 2, выполнять (DO) инструкцию или
блок. Например, для инструкции
FOR 1: = 3 DOWNTO 1 DO WRITELN (’1 =£’, 1:1);
на экран дисплея будут выведены три строки?:
1 = 3
1 = 2
I = 1
В приведенных выше инструкциях FOR, ТО, DOWNTO,
DO—зарезервированные слова. Если значение первого
выражения превышает последнее (для ТО) или меньше
последнего (для DOWNTO), инструкция (блок), стоящая
после DO, не выполняется ни разу.
Инструкция с оператором WHILE записывается в сле-
дующей форме:
170
WHILE логическое выражение DO инструкция или блок;
Логическое выражение, стоящее после зарезервиро-
ванного слова WHILE, называется условием возобнов-
ления цикла. Тело цикла повторяется до тех пор, пока
истинно (принимает значение TRUE) условие возобнов-
ления. Как только логическое выражение принимает
значение FALSE (ложно), осуществляется переход к сле-
дующей инструкции. Если условие возобновления не
удовлетворяется до начала выполнения цикла, тело цикла
пропускается.
Инструкции с оператором REPEAT записываются в
следующей форме:
REPEAT одна или несколько инструкций UNTIL логическое
выражение;
В операторе REPEAT проверка условия выхода осу-
ществляется в конце, а не в начале цикла, поэтому его
тело (одна или несколько инструкций после зарезерви-
рованного слова REPEAT) выполняется по крайней мере
один раз. Тело цикла повторяется до тех пор, пока условие
выхода, записанное после зарезервированного слова
UNTIL, ложно. В отличие от циклов типа FOR и WHILE
между словами REPEAT и UNTIL можно поместить как
одну, так и несколько инструкций, причем в последнем
случае не требуются операторные скобки типа BEGIN
и END;.
Для реализации условных переходов в языке ПАС-
КАЛЬ используются два оператора — IF и CASE. Без-
условный переход осуществляется с помощью оператора
GOTO.
Запись инструкции с оператором IF представляется
в одной из следующих двух форм:
1) IF логическое выражение THEN инструкция 1 или блок 1 ELSE
инструкция 2 или блок 2;
2) IF логическое выражение THEN инструкция 1 или блок 1;
инструкция 2 или блок 2;
В первой форме, если логическое выражение, следую-
щее после IF, истинно (принимает значение TRUE), вы-
бирается инструкция 1 (блок 1), записанная после заре-
зервированного слова THEN. В противном случае выби-
рается инструкция 2 (блок 2), следующая за словом
ELSE (иначе), при этом инструкция 1 (блок 1) про-
пускается. Зарезервированному слову ELSE не должна
предшествовать точка с запятой.
171
Во второй форме, если логическое выражение, сле-
дующее после IF, истинно, выбирается инструкция 1
(блок 1). В противном случае инструкция 1 (блок 1) про-
пускается и выбирается следующая за ней инструкция
2 (блок 2). Здесь инструкция 2 выполняется всегда, а
инструкция 1 либо выполняется, либо нет.
В инструкции IF непосредственно после зарезерви-
рованных слов THEN и ELSE должны следовать другие
инструкции (блоки). Если хотя бы одна из них является
инструкцией IF, ее называют вложенной. Согласно при-
нятому в ПАСКАЛе соглашению, слово ELSE всегда
относится к ближайшему предшествующему ему IF.
Оператор CASE позволяет осуществить выбор одной
из нескольких альтернатив. Запись CASE начинается
со строки
CASE выражение OF
Выражение, стоящее между зарезервированными сло-
вами CASE и OF, называется селектором. Запись инструк-
ций с оператором CASE можно представить в следующей
форме:
CASE выражение
константа 1 (группа констант 1): инструкция 1;
константа п — 1 (группа констант п—1): инструкция п — 1
ELSE инструкция п
END;
Константа 1 (группа констант 1), ..., константа п— 1
(группа констант п — 1) называются метками случаев
(их не надо объявлять, т. е. записывать, после зарезер-
вированного слова LABEL). Сначала вычисляется значе-
ние селектора, затем выполняется инструкция, перед
которой стоит метка со значением, совпадающим с вы-
численным значением селектора. Если такой метки нет,
выполняется инструкция ELSE. Запись ’’ELSE инструк-
ция п” может отсутствовать. Тогда, если значение селек-
тора не совпадает со значениями меток, не выполняется
ни одна инструкция (осуществляется переход к оператору
END;). Выражение-селектор может относиться к любому
типу, кроме REAL. Метки случаев должны принадлежать
тому же типу, что и селектор. Недопустимо, чтобы одна
и та же метка появлялась более одного раза в одной ин-
струкции CASE.
Оператор безусловного перехода представляется в
следующей форме:
172
GOTO метка,
Оператор GOTO указывает, что выполнение програм-
мы необходимо продолжить с инструкции, помеченной
меткой. Метка должна быть описана в разделе LABEL
той программы, в которой она используется. В качестве
меток можно применять идентификаторы и целочисленные
константы. В объявлении LABEL различные метки пере-
числяются через запятую, а после последней метки ста-
вится точка с запятой. Например:
LABEL 1, STOP, 14;
Здесь 1, STOP и 14 — три метки. Если метка исполь-
зуется в операторе GOTO, она обязательно должна по-
явиться где-то еще в программе. При этом в строке про-
граммы указывается метка, ставится двоеточие и запи-
сывается инструкция. Например:
1: инструкция;
ИЛИ
STOP' инструкция;
В заключение оговорим правила использования в
инструкциях ПАСКАЛя точки с запятой. Она вводится
для разделения двух идущих друг за другом инструкций,
которые могут записываться в одной или разных строках.
Необходимо помнить два следующих правила:
1) перед ключевым словом ELSE точка с запятой не
ставится;
2) точку с запятой не обязательно ставить перед за-
резервированным словом END.
В ПАСКАЛе допустимы сочетания ;; и ;END, т. е. счи-
тается, что после первой точки с запятой стоит фиктивная
или пустая инструкция. Наличие таких инструкций не
влияет на эффективность программы.
Вследствие ограниченности объема пособия примеры
программ на языке ПАСКАЛЬ здесь не приводятся.
Большое число различных программ с содержательными
комментариями, иллюстрирующих выполнение описанных
операторов, дано в работе [10].
5.4. СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ
В программе на языке ПАСКАЛЬ можно использовать
структурированные типы данных, которые являются
различными комбинациями рассмотренных ранее простых
173
типов. К ним относятся массивы, множества, записи,
файлы и строки символов.
Массив включает совокупность элементов одного типа.
Ко всему массиву целиком можно обращаться по имени.
Кроме того, можно выбирать любой элемент массива.
Для этого необходимо задать индекс, который указывает
его относительную позицию. Число элементов массива
определяется при его объявлении и в дальнейшем не
меняется. Если массив объявлен, к любому его элементу
можно обратиться следующим образом: указать имя мас-
сива и индекс элемента в квадратных скобках. Массив
объявляется в следующей форме:
ARRAY [тип индексов 1, ..., тип индексов п] OF тип элементов массива;
Здесь ARRAY и OF — зарезервированные слова; п — чис-
ло измерений массива. Например, одномерный массив
MAS1 из 7 элементов целого типа можно объявить одним
из следующих двух способов:
TYPE R= ARRAY [1..7] OF INTEGER;
VAR MASI : R;
ИЛИ
VAR MASI:ARRAY [1..7] OF INTEGER;
При первом способе введен новый тип R и объявлена
переменная MAS1 типа R; при втором переменная MAS1
сразу объявлена как соответствующий массив. Чтобы
присвоить некоторому элементу массива определенное зна-
чение (например, пятому элементу MAS1 значение 2),
достаточно записать инструкцию присваивания вида
имя массива [индекс элемента] := заданное значение;
Например: MAS 1(5] :=2;
Двухмерный массив объявляется теми же способами.
Так, для массива MAS2 вещественного типас,с измерени-
ями 4 и 9 можно записать:
TYPE B = ARRAY [1..4, 1..9] OF REAL;
VAR MAS2:B;
ИЛИ
VAR MAS2:ARRAY[1..4,1..9] OF REAL;
По аналогии объявляются массивы с большим числом
измерений. В качестве индекса при обращении к элементу
массива можно использовать выражение, тип которого
должен совпадать с типом индекса; последний может
быть любым, кроме REAL. Наиболее часто в качестве
174
индекса выступает константа или переменная. Элементы
массива могут быть данными любого типа (для большин-
ства трансляторов, за исключением типа файл).
В языке ПАСКАЛЬ допустимы массивы, содержащие
три и более измерений. Например, массив можно объявить
так:
VAR М: ARRAY[1..25, 1..4, 1..8, 1..17] OF BOOLEAN;
Тогда обращение к элементу массива осуществляется
следующим образом: M[I, J, К, L], где I, J, К, L— значе-
ния индексов.
Множеством называют совокупность объектов. В языке
ПАСКАЛЬ оно может состоять из произвольного числа
элементов одного типа, а может и не содержать элементов
(пустое множество). Объявление множеств осуществляет-
ся с помощью зарезервированного слова SET в следующем
формате:
множество= SET OF тип элементов множества;
Например: запись
TYPE M=SET OF BOOLEAN;
определяет множество М, элементы которого могут при-
нимать два значения: TRUE и FALSE. Тип, которому
должны принадлежать все элементы множества, называет-
ся базовым. Он может быть любым, кроме REAL и
POINTER. Допустимое количество элементов в множестве
ограниченно. В связи с этим обычно недопустимо объяв-
ление типа
SET OF INTEGER;
поскольку целые значения могут находиться и вне допу-
стимого диапазона.
В программе на ПАСКАЛе множество задается в виде
списка элементов (через запятую), заключенных в квад-
ратные скобки. Элементом может быть константа, пере-
менная, выражение. Допускается запись интервала значе-
ний — пары элементов, разделенных двумя точками.
Рассмотрим возможные операции над множествами
М и N. Оператор объединения (-(-) позволяет получить
новое множество M-|-N, элементы которого принадлежат
хотя бы одному множеству М или N. Так, если М= [ 1, 2, 3],
N= [3, 4, 5], то M-|-N=[l, 2, 3, 4, 5]. Оператор
пересечения (*) позволяет получить новое множество
M*N, элементы которого принадлежат одновременно М и
N. Например, для заданных выше множеств M*N= [3].
175
Пустое множество в языке ПАСКАЛЬ записывается в виде
двух рядом расположенных квадратных скобок ([]). Опе-
ратор разности (—) позволяет получить новое множество
М — N, элементы которого принадлежат М, но не включе-
ны в N. Так, для заданных выше множеств М — N = [ 1,2] а
N—М= [4,5].
Оператор IN позволяет определить, принадлежит эле-
мент множеству или нет (он эквивалентен знаку £ в мате-
матике). Если М= [’А’, ’В’], то выражения ’A’ IN М;
’В’ IN М принимают истинное значение, а выражение
’С’ IN М — ложное.
При работе с множествами можно использовать симво-
лы отношения. Операторы=и < ) имеют в математике
аналоги=и=^= и позволяют установить, равны два множе-
ства или нет. Операторы <= и )= имеют в математике
аналог П); 2) +, — (имеют в математике аналоги U и \);
3) IN, =, <>, <=, > = .
Расположим операторы для работы с множествами в
порядке убывания их приоритета: 1)* (имеет в математике
аналог П ); 2) + , — (имеют в математике аналоги (J и \);
3) IN, =, <>, <=, > = .
Запись, как и массив, представляет собой совокуп-
ность данных. Отличием является то, что к ее элементам
необходимо обращаться по имени и что различные элемен-
ты записи не обязательно должны принадлежать одному
типу. Записи удобно использовать там, где разнообразные
данные, относящиеся к одному и тому же объекту, необ-
ходимо объединять. Объявление записей осуществляется с
помощью зарезервированного слова RECORD в следую-
щей форме:
RECORD
имя поля 1: тип поля 1;
имя поля п: тип поля п;
END;
Именем поля может быть любой идентификатор. На-
пример:
TYPE DATA ;
HECOHDS
DH; I..31;
MONTH- 1..I2;
YEAR: 1920..2100:
Ш,
HAN ;
HECOHDS
NAME: ARRAY£I..2O1 OF CHAR;
BO: SATA;
V: 1..I00:
END,
176
Тип DATA включает три поля: DAY, MONTH и YEAR.
Все они являются интервальными. Тип MAN тоже содер-
жит три поля: NAME, BD и V. Тип NAME — это массив из
20 символов. Объект BD представлен составным полем
DATA. Поле V является интервальным. После введения
типов DATA и MAN можно объявить переменные, значе-
ния которых принадлежат этим типам. Например:
VAR MANS: ARRAY [ 1 „200] OF MAN;
Здесь определен массив MANS, состоящий из 200 элемен-
тов типа MAN.
В языке ПАСКАЛЬ разрешено использовать массивы
записей; записи могут состоять из массивов, множеств
и других записей. Чтобы обратиться к отдельному эле-
менту записи, необходимо указать его имя, поставить
точку и сразу за ней написать имя нужного поля (сфор-
мированное таким образом имя часто называют состав-
ным) . Например:
MANS[I]. V: = 67;
MANS [I]. BD.DAY:=10;
MANS [I] ,BD.MONTH:= 5,
В инструкциях присваивания разрешается использо-
вать не только имена полей, но и имена записей. Например:
VAR BD1, BD2: DATA;
BEGIN............
BD1 := BD2~......
end'.............
Присваивание значений всем элементам записи требует
большого числа длинных выражений вида
MANS [I] ,BD.YEAR:= 1981;
Для сокращения длины подобных строк введен опе-
ратор, определяемый зарезервированным словом WITH.
Соответствующая инструкция имеет вид
WITH имя записи DO инструкция;
Ее следует использовать, если работа ведется с несколь-
кими полями одной и той же записи. В этом случае
можно только один раз указать имя записи (после слова
WITH), а имена полей использовать как простые перемен-
ные, не употребляя вместе с ними имя записи. Например:
177
WITH MANS[I] BO
BEGIN
NAME" 'МАТОАВЙ ВАСИЛЬЕВИЧ';
WITH BD DO
BEGIN
DAY::!!; MONTH::!; YEAR::I928;
END;
V-.--6I;
END;
Конструкцию, состоящую из двух инструкций WITH:
WITH имя записи DO WITH имя поля записи DO инструкция;
можно записать короче:
WITH имя записи, имя поля записи DO инструкция;
Например:
WITH MANSII], BD DO
BEGIN
DAYt-14; MONTH::!; YEAR:=I928;
END;
На практике часто необходимы записи с близкими, но
не идентичными структурами. Так, могут рассматриваться
три варианта различных полей, а в конкретном экземпля-
ре записи будет выбран только один из них. Для подобных
целей используются структуры, называемые записями с
вариантами. Различные варианты выбираются с помощью
оператора CASE, который вводится в объявление записи
(между зарезервированными словами RECORD и END;).
Еще одно слово END в инструкции CASE не нужно.
Общая форма представления записей с вариантами
будет такой:
RECORD
ИШ 1Ш I: тип пои I;
имя подя а- тип поля п,
САВЕ поле признака: тип пои признака (его возиохине
значения) OF
имя метки ди варианта !• (имя поля; тип поля; имя
ПОЛИ: тип поля; . . );
иия метки для вариаита а; (иии поля- тип поли; и№
поля: тип поли; ... );
END;
Приведем пример фрагмента программы:
TYPE Z - (В,Т);
TV = (F,V,B);
RECORD
CL: I..19;
CASE FRIZ: 2 OF
S; (V:TV; RrBOOLEAN);
T: (КАТИ .6);
END;
178
В соответствующей программе заполняется одно из
вариантных полей, выбираемое по значениям PRIZ=S
или PRIZ=T.
Данные, предназначенные для длительного хранения,
размещаются в файлах. Имя и тип файла образуются по
правилам, принятым в ОС MS-DOS (см. гл. 3).
Объявление файла имеет следующий формат:
FILE OF тип элементов файла;
Здесь использовано зарезервированное слово FILE. При-
ведем примеры объявлений:
TYPE Fl = FILE OF REAL;
VAR FL:F1;
ИЛИ
VAR FL:FILE OF REAL;
Тип компонентов файла может быть любым, за исключе-
нием типа «файл».
Для установления связи между файлом в программе и в
физическом файле на внешнем устройстве используется
процедура ASSIGN в следующем формате:
ASSIGN(hmh файла, ’спецификация файла’);
После реализации процедуры ASSIGN обращение к
файлу в операциях над файлами означает выполнение
операций над соответствующим файлом на внешнем уст-
ройстве. Заметим, что переменные типа FILE не могут
использоваться в выражениях или в операторах присваи-
вания.
Рассмотрим пример. Пусть задано:
ASSIGN(FL,’A:SP.F’);
и предварительно объявлено:
TYPE Fl = ARRAY[1..15] OF CHAR;
VAR FL.-FILE OF Fl;
t. e. FL — имя файла, элементы которого— 15-символьные слова
Процедура ASSIGN устанавливает взаимно однозначное соответ-
ствие между именем FL файла в программе и физическим файлом с
составным именем SP.F на диске А.
Файл открывается для чтения с помощью процедуры
RESET:
RESET(hmh файла);
Так, для файла с именем FL будет записано:
RESET(FL);
179
Файл открывается для записи с помощью процедуры
REWRITE:
REWRITE (имя файла);
Например, для файла с именем FL будет записано:
REWRITE (FL);
Процедура REWRITE уничтожает содержимое файла.
Запись в файл и чтение информации из файла можно
осуществлять с помощью процедур READ (READLN),
WRITE (WRITELN). В этом случае используются такие
формы:
READ (имя файла, имя переменной);
WRITE (имя файла, имя переменной или выражение);
Предположим, что файл FL открыт для чтения проце-
дурой RESET. Запишем следующую инструкцию:
READ(FL, I);
В результате значение текущего элемента файла FL будет
присвоено переменной I и осуществляется переход к сле-
дующему элементу.
Если записать инструкцию:
WR1TE(FL, I);
то значение переменной I записывается в файл FL. Запись
и чтение данных осуществляются в ту область, которую
адресует указатель текущей позиции (текущего элемента)
файла. При выполнении чтения указатель смещается на
позицию в сторону начала файла, а при выполнении
записи — к концу файла.
Еще одна процедура — CLOSE — используется для
закрытия файла, когда все действия с ним закончены. Ее
формат:
CLOSE (имя файла); ,,
Например, для файла FL будет записано:
CLOSE (FL);
Строки символов представляют собой последователь-
ности символов и аналогичны массивам с типом CHAR.
Их отличием является то, что число символов, или длина
строки, может динамически меняться в интервале от нуля
до заданного верхнего значения. Объявление строки сим-
волов осуществляется с помощью зарезервированного сло-
ва STRING и представляется в следующей форме:
180
STRING [максимальная длина строки];
Здесь длина строки — это целочисленная константа, ле-
жащая в определенном интервале (обычно от 1 до 255).
Приведем примеры объявлений:
TYPE FAM= STRING [20];
NAME= STRING [30];
VAR F:FAM;
N:NAME;
Для хранения в ПЭВМ каждого символа строки обыч-
но требуется один байт. Строковая переменная (типа F и
N) занимает в памяти ПЭВМ на один байт больше, чем
необходимо для ее размещения согласно объявлению. Чи-
сло в дополнительном (нулевом) байте определяет в дан-
ный момент времени длину строки (от 1 до 255).
Как и к массиву, к отдельным символам строки можно
обратиться с помощью индексов в квадратных скобках,
например F[5]. Нулевой индекс определяет позицию, в
которой содержится длина строки.
Рассмотрим операторы, позволяющие производить опе-
рации над строками. Оператор сцепления (~|~) обеспечи-
вает соединение значений строк, указанных в качестве
операндов. Результатом является строка, длина которой
равна сумме длин строк операндов. Например, если
F:= ’РОС’+’СИЯ’, то значением F будет РОССИЯ.
Операторы отношения (), (, =, )=, <=), имею-
щие более низкий приоритет, чем операторы сцепления,
позволяют реализовать сравнение строк. Как и выше, ре-
зультат имеет логический тип и принимает значение
TRUE, если соответствующее выражение истинно, и
FALSE — в противном случае. Сравнение строк произво-
дится посимвольно слева направо. Обозначим через i и j
но.мера символов соответственно в первой и второй стро-
ках. Если символы 1, 2,..., i — 1 первой строки совпадают
с символами 1, 2,..., i—1 второй строки (i=j), а символ i
первой строки не совпадает с символом j второй, то боль-
шей считается строка, для которой символ (i или j) имеет
большее значение кода в таблице кодов ПЭВМ. Если
строка имеет длину i и ее последовательность из i символов
совпадает с последовательностью из i символов второй
Строки, длина которой больше i, то строка, которая короче
(в данном случае — первая), считается меньшей.
Для построения выражений над строками используют-
ся рассмотренные выше правила. Строковый тип полно-
стью совместим с типом CHAR, в результате чего строко-
181
вне и символьные переменные и константы разрешено
использовать в одном выражении. Значение строкового
выражения можно присвоить строковой переменной с по-
мощью оператора присваивания. Если длина присваивае-
мого значения больше заданной максимальной длины
строковой переменной, лишние символы справа пропада-
ют. Если значение строкового выражения присваивается
переменной типа CHAR, длина строки должна быть равна
единице.
5.5. ПРОЦЕДУРЫ И ФУНКЦИИ
В языке ПАСКАЛЬ существует два типа подпро-
грамм — процедуры и функции. Они представляют собой
автономные блоки, имеющие имена, к которым можно
обращаться.
В программу с подпрограммами включается дополни-
тельный фрагмент для определения процедур и (или)
функций (см. рис. 5.1). Он может содержать части
(одну или обе), на которые указывают стрелки. Первая
часть — это объявление процедур и (или) функций,
оформленных ранее в виде отдельных файлов. Такие под-
программы могут разрабатываться независимо от вызы-
вающей программы. Их исходные тексты заносятся в
файлы на диске. На этапе трансляции с помощью специ-
альных директив обеспечивается включение подпрограмм
в вызывающую программу. Наличие такой возможности
позволяет пользователю создавать личные библиотеки (на
диске) наиболее часто употребляемых им процедур и функ-
ций. Вторая часть — это определение подпрограмм в са-
мой вызывающей программе. Процедура задается в такой
форме:
PROCEDURE имя (список параметров);
Объявление локальных переменных (констант)
Определение процедур и (или) функций ,,
BEGIN
Тело процедуры
END;
В ПАСКАЛе процедурой называется часть программы,
имеющая имя и предназначенная для решения поставлен-
ной задачи. При ее определении указываются имя и список
параметров, значения которых передаются процедуре или
получаются из нее (такой список может и отсутствовать).
Процедуре разрешено обращаться к подпрограммам более
низкого уровня, и тогда она включает соответствующее
182
определение. Так формируется иерархическая структура
программного комплекса. Тело процедуры ограничивается
операторными скобками BEGIN и END; (после END ста-
вится точка с запятой).
Функция определяется в следующей форме:
FUNCTION имя (список параметров): тип функции;
Объявление локальных переменных(констант)
Определение процедур и (или) функций
BEGIN
Тело функции
END;
Она отличается от процедуры только тем, что всегда
возвращает в точку вызова свое значение. В связи с этим
в первой строке определения после двоеточия необходимо
указывать тип функции (тип возвращаемого значения).
Чтобы возвратить результат в вызывающий модуль, не-
обходимо имени функции присваивать значение.
Каждая подпрограмма определяется только один раз,
но может использоваться многократно. Когда она объяв-
лена, ее можно вызвать в теле программы, просто зада-
вая имя, за которым, если необходимо, следует список
параметров. Соответствующие инструкции называются
вызовом подпрограмм. Вызов процедуры (функции) при-
водит к выполнению инструкций, составляющих ее тело,
после чего будет выбрана следующая за вызовом ин-
струкция. Порядок следования параметров в списке и в вы-
зове процедуры (функции) важен, так как определяет, ка-
кому параметру будет присвоено то или иное значение.
Первому параметру в списке соответствует первый пара-
метр в вызове, даже если их идентификаторы разные. То
же правило имеет место и по отношению к последующим
параметрам. Передаваемое значение и соответствующий
ему параметр должны относиться к совместимым типам.
В процедуре (функции) можно объявлять константы,
типы, переменные (непосредственно после заголовка, т. е.
так же, как это делается в основной программе). Все
объявленные идентификаторы и те, которые содержатся в
списке параметров, являются локальными для рассматри-
ваемой подпрограммы. Область их действия — соответ-
ствующая процедура или функция, а также любая вло-
женная подпрограмма.
Идентификаторы, объявленные в главной программе,
являются глобальными. Вызывающему модулю недоступ-
ны значения локальных переменных, определенных в дру-
гой подпрограмме. Однако процедуре или функции могут
183
быть доступны значения глобальных переменных. Если
идентификатор является глобальным, т. е. объявлен в
главной программе, все входящие в состав этой главной
программы подпрограммы могут обращаться к нему, но
только в том случае, если в них нет другого объявления
для этого идентификатора. Любое объявление идентифи-
катора в процедуре (функции) делает недоступным объ-
ект, имеющий то же самое имя и объявленный во внешней
по отношению к процедуре (функции) части программы.
Рассмотрим, как соответствуют друг другу параметры
в вызове и в списке процедуры. Пусть вызывающая
программа обращается к процедуре
PROCEDURE имя (VAR F,G: тип; А, В, С, D: тип);
с помощью инструкции:
имя(К, L, М, N, I, J);
Значения К, L должны быть получены в подпрограмме
и переданы в вызывающую программу. Чтобы заключи-
тельное значение параметра было передано в вызывающую
программу, необходимо поставить зарезервированное сло-
во VAR перед списком параметров, стоящим в заголовке
процедуры. Оно свидетельствует о том, что при вызове
процедуры надо использовать имя переменной, а не выра-
жение или константу. Значения М, N, I, J передаются
в подпрограмму и используются только в ней (их заключи-
тельные значения не возвращаются в вызывающую про-
грамму). Поэтому в заголовке процедуры перед парамет-
рами А, В, С, D слово VAR ставить не надо. Соответствие
между параметрами в вызове и в списке будет такое:
К—F, L—G; М—A; N—В; I—С; J—D. Передача пара-
метров в функцию осуществляется по тем же правилам,
что и для процедуры.
Рассмотрим допустимый в языке ПАСКАЛЬ специаль-
ный способ вызова, называемый реку речей."В этом случае
процедура или функция может вызывать саму себя. Важ-
ным моментом при составлении рекурсивной подпрограм-
мы является организация выхода. Здесь легко допустить
ошибку, состоящую в том, что подпрограмма будет по-
следовательно вызывать саму себя бесконечно долго.
Поэтому рекурсивный процесс должен шаг за шагом так
упрощать задачу, чтобы в конце концов для нее появилось
нерекурсивное решение.
Две процедуры (функции) являются взаимно рекур-
сивными, если первая вызывает вторую, а вторая — пер-
184
вую. Первая подпрограмма должна быть определена с са-
мого начала. Однако в этот момент вторая процедура
(функция) еще не определена. Зарезервированное слово
FORWARD позволяет объявлять имя процедуры (функ-
ции), отложив при этом ее определение.
Объявление подпрограмм производится в два этапа. На
первом задаются имя процедуры (функции) и список пара-
метров, за которым следует зарезервированное слово
FORWARD. Затем производится полное определение про-
цедуры (функции), но в него не входят параметры, уже
описанные выше.
Рассмотрим примеры [10]. Первый из них позволяет найти наи-
больший общий делитель двух целых положительных чисел:
PBOGBAH EECUBS:
VAB Н,Н:IHTEGEB;
FUNCTION NOD(A,В:IHTEGEB):IHTEGEB;
{ объявление рекурсивной функции NOD целого типа }
VAB С: IHTEGEB;
BEGIN
IF В>А ТВЕН C:=NOD(B,A) { если В>А, то в Минин HOD
параметры меняются местами }
ELSE
IF Bed ТВЕН С:4 { если ВсО, то нерекурсивный
выиод 1
ELBE
C;=HOD(B,A ИОВ В); { здесь A MOD В - остаток от
делении А на В )
NOD::C; { выгод нз функции )
END;
BEGIN
NBITELN1'ВВЕДЕТЕ НЕРВОЕ Н ВТОРОЕ ЧИСЛО');
BEAD(N,N); HBITELN;
MBITELHI 'ЯАНБОЛЫМ ОБЩА ДЕЛИТЕЛЬ:',NOD(N,M):4);
{ в инструкции WRITE происходит обращение к Функции
NOD; вычисленное значение NOD(N,M) выводится на
экран дисплея }
END.
Вторая программа позволяет найти наибольший общий делитель
трех целых положительных чисел А, В, С. В ней процедура PR2 вызы-
вает PR1. Процедура PR1 вызывает саму себя и процедуру PR2:
PBOGBAM ВЕК4;
FAB A,B,C,D:INTEGER;
PROCEDURE PRI(A,B,C:INTEGER); FORWARD;
( ироцедура FBI объивляется здесь, а окончательно
определяется ниде }
PROCEDURE PR2(A,B,C.-INTEGER);
BEGIN
IF B<C TBEN PB1(A,C,B)
ELSE PRI(B,A,C);
185
{ вызов процедуры PHI, которая в свов очередь
вызывает эту процедуру (Р82). Здесь пара-
метры в вызове ненавтси местами }
END; { конец процедуры Р82 }
PBOCEDUHE Р8г, { определение процедуры PBl. Ее параметры
уде описаны виде, ы здесь ид приводить
не надо }
BEGIN
IF(A>:8) AND (В>-С) ТВЕН
BEGIN
IF(B=O) AND (0=0) ТВЕН D:=A
{ нерекурсивный вндод }
ELSE PBI(B,A HOD В,С)
{ рекурсивный внзов процедуры PHI }
END ELSE РН2(А,В,С);
{ упорядочение значений А, В, С в процедуре Р82 }
END; { конец процедуры PHI }
BEGIN { начало тела ирограммы }
WHITELH('ВВЕДИТЕ ПЕРВОЕ, ВТОРОЕ И ТРЕТЬЕ ЧИСЛО');
8EAD(А,В,С); WHITELH;
WHITEUl('А=',А:5,' В=',В:5,’ С=',С:5);
Р8!(А,В,С);
WHITELH( 'НЙНЕОЛЬИНЙ ОБЩА ДЕЛИТЕЛЬ: ',D:5);
END. { конец тела программы }
Большую группу подпрограмм составляют библиотеч-
ные процедуры и функции. Они заранее определены и
используются для выполнения часто встречающихся
вычислительных операций и преобразования данных.
5.6. ДИНАМИЧЕСКИЕ СТРУКТУРЫ ДАННЫХ
В программах на языке ПАСКАЛЬ допускается дина-
мическое выделение и освобождение оперативной памяти в
ходе решения задачи. Организация данных с динамически
изменяемой структурой рассматривается на примере при-
веденной ниже программы NEWDIS [10]:
P80G8AN HINDIS;
TYPE ZAP='BUK; { переменные типа 2АР моно непосредст-
венно нсиодьзовать дин ссылок на данные типа ВПК }
вик=
8EC08D
В:СВАЕ;
В:2АР;
END; { объавленне заинсей типа ВПК }
TAB HAST,SL;ZAP;
SIH-.CBAB;
BEGIN
HAST:=HIL; { зарезервированное слово HIL определяет
специальный пустой указатель }
ИИЕЬНСВВЕДТЕ СТРОКЕ СИМВОЛОВ');
8ЕРЕАТ
EEAD(SIM); { с клавиатуры вподитея очередной
символ ВШ }
SL:=NAST; { адрес настоящей заинси HAST ирнсван-
ваетсн следувцей записи ВЬ }
186
HEW(NAST); { резервируется область панати, достаточ-
на! ддя размеренна одного элемента
типа HAST }
HAST' B:=SIH; { в поле В записи BAST" записывается
введенный символ SIH }
HAST'.U-.xSL; { в поле В записи HAST" запнсываетсв
адрес SB фактически предыдущей записи
(си. инструкции SL::NAST) }
UNTIL SIM:'.'; { цикл повторвется до тех пор, иода зна-
чением переменной SIM не станет точка }
НЕРЕАТ
WBITE(HAST'.В); { внвод на экран дисплея символа, за-
писанного в ноле В записи NAST )
SL;-HAST'.8; { St принимает значение адреса следую-
щей записи NAST, которнй передается
из поля В )
BIEPOSE(HAST); { освобождается область памяти, кото-
рая ранее отводилась ди размещения
элемента типа NAST |
NAST.:SL; ( адрес NAST настоящей завися принимает
значение адреса SL следующей записи, и
все рассмотренные действии повторвются )
UNTIL NASMIL;
NHITELN;
END.
Строка TYPE вводит указатели для ссылок на значения
типа BUK. Объект BUK — это запись, состоящая из двух
полей: ВиО. Переменные NAST и SL имеют тип ZAP
(т. е. это указатели на записи); SIM — тип CHAR. Про-
грамма NEWDIS позволяет вводить с клавиатуры после-
довательность символов любой длины до первой встретив-
шейся точки и выводить их на экран дисплея в обратном
порядке. Процедуры NEW(NAST) и DISPOSE(NAST)
используются в программе для динамического распреде-
ления памяти. Первая из них резервирует область памяти,
достаточную для размещения одного элемента типа NAST,
вторая освобождает указанную область. В программе
используется специальная константа NIL. Если значением
указателя является NIL, то он не обращается к конкретно-
му объекту. Переменная NAST имеет значение адреса
(местоположения) в памяти, где помещена одна запись
типа BUK. К этой записи два поля: В и U. NASTA.B и
NASTA.U — это то, что записано в поле Вив поле U (зна-
чения полей В и U). Таким образом, если некоторая
переменная А — это указатель ссылочного типа, то АЛ —
значение объекта, на который она указывает.
При вводе информации с клавиатуры с помощью про-
цедуры NEW в памяти резервируется место для очередной
записи. В поле В этой записи заносится значение введен-
ного символа SIM, а в поле U запоминается адрес преды-
187
дущей записи. При чтении информации символ из поля В
очередной записи выводится на экран дисплея, на основа-
нии данных в поле U определяется адрес предыдущей
записи, с помощью процедуры DISPOSE освобождается
память под текущую запись и реализуется переход к
предыдущей записи.
Ввод данных в программу NEWDIS осуществляется
посимвольно: после набора каждого знака ' нажимается
клавиша ВВОД. Вывод информации на экран будет реали-
зован после ввода первой точки. Например, если ввести
строку АВС., то результат будет СВА.
6. АЛГОРИТМИЧЕСКИЙ ЯЗЫК СИ
6.1. ПРОГРАММЫ И ДАННЫЕ
В языке СИ любая программа состоит из одной или бо-
лее функций. Различным функциям можно давать какие
угодно имена. Среди них есть одно особое — main; выпол-
нение любой программы начинается с функции main.
Общая структура программы на языке СИ, содержащей
единственную функцию main, представляется в следующем
виде:
main ()
Тело программы
Здесь мы будем рассматривать версию 2.0 языка
ТУРБО СИ. Несмотря на это, большая часть представлен-
ного материала имеет отношение и к другим системам
программирования аналогичного назначения.
Одним из механизмов взаимодействия между функци-
ями являются аргументы. Список аргументов в круглых
скобках идет следом за именем функции; наша функция
main аргументов не имеет, поэтому список выглядит так:
( ). Фигурные скобки {и} обрамляют начало и конец тела
программы (далее мы увидим, что они используются и для
других целей).
Тело программы состоит из последовательности ин-
струкций (команд), предписывающих действия на опреде-
ленном шаге ее выполнения. Инструкции составляются
из операндов и операторов. Для представления операто-
ров используются зарезервированные слова, назначение
которых зафиксировано.
В СИ каждый оператор, а также каждая строка с
обращением к функции, оканчивается точкой с запятой (;).
Исключение составляют команды макропроцессора и име-
на функций, стоящие в начале программной единицы
(например, main()). Обратим внимание на то, что фигур-
189
ные скобки { ) только обрамляют операторы, и точку с
запятой после них ставить не надо.
Ниже показана еще одна структура программы, в ко-
торой функция main производит обращение к другой
функции fun. Последняя выполняет роль подпрограммы и
тоже не содержит аргументов:
main ()
Тело программы, в котором есть
обращение к функции fun
fun ()
Тело функции fun
При написании инструкций СИ используются опреде-
ленные символы, составляющие алфавит языка, который
включает латинские прописные и строчные буквы, цифры
и специальные знаки. Специальные символы (каждый в
отдельности либо в комбинации друг с другом) позволяют
задавать операторы и знаки операций. В табл. 6.1. показа-
Таблица 6.1
Знак операции Назначение операции Порядок выполнения
1 2 3
0 Вызов функции 0,633 напРаво [] Выделение элемента массива Выделение элемента записи -* Выделение элемента записи ! Логическое отрицание Справа налево ~ Поразрядное отрицание — Изменение знака -f- 4- Увеличение на единицу «, Уменьшение на единицу & Взятие адреса * Обращение по адресу (тип) Преобразование типа sizeof Определение размера в байтах * Умножение Слева направо / Деление % Определение остатка от деления 4- Сложение Слева направо — Вычитание « Сдвиг влево Слева направо » Сдвиг вправо
190
Окончание табл. 6.1
2 3
< — Меньше, чем Меньше или равно Больше, чем Больше или равно Слева направо
I — Равно Не равно Слева направо
]& Поразрядное Логическое И Поразрядное Исключающее ИЛИ Поразрядное Логическое ИЛИ Слева направо Слева направо Слева направо
&& Логическое И Логическое ИЛИ Слева направо Слева направо
?• Условная (тернарная) операция Справа налево
= Присваивание Справа налево
ZI1 = Здесь zne(*, /, %, —, «, », &, * например а* = Ь; Операция запятая G). Слева направо
но, какие комбинации символов используются в языке для
обозначения различных операций. Эта таблица дополни-
тельно определяет приоритет выполнения операций и будет
широко применяться далее.
Среди других комбинаций символов часто используют-
ся: /*, */— для записи комментариев; ” — для задания
символьной информации (например, в случае ее вывода на
экран дисплея или принтер); ’ — для задания символьных
констант; ; — для завершения каждой инструкции и стро-
ки с вызовом функции.
Важным понятием языка является идентификатор, ко-
торый используется в качестве имени объекта (функции,
переменной, константы и т. п.). Как и в ПАСКАЛе, иден-
тификатор может включать латинские буквы, цифры и сим-
вол подчеркивания, причем первым символом должна быть
не цифра. В СИ буквы нижнего регистра (a,...,z), исполь-
зуемые в идентификаторах, отличаются от букв верхнего
регистра (A,...,Z). Это означает, что считаются разными
идентификаторы: prog, ProG, PROG, pRoG и т. п.
В языке различают понятия описание переменной и
определение (объявление) переменной. Описание устанав-
ливает свойства объекта: его тип, размер и т. п. Объяв-
ление наряду с этим вызывает выделение памяти.
Каждый простой тип данных определяется одним из
следующих зарезервированных слов (наряду с основными
типами здесь перечисляются также модификаторы типов):
191
1) int (целый). Для 16-разрядных ПЭВМ диапазон
возможных целых значений лежит в пределах от —32768
до 32767. В ТУРБО СИ переменная типа int занимает 16
бит (2 байта);
2) short (короткий целый). Соответствующие объекты
не будут больше, чем int. В ТУРБО СИ переменная
типа short, как и int, занимает 16 бит;
3) long (длинный целый). Как и выше, соответствую-
щие объекты не могут быть меньше int. В ТУРБО СИ
переменная типа long занимает 32 бита (4 байта) и по-
зволяет представлять числа от —2147483648 до
2147483647;
4) char (символьный). Этот тип задает значения, ко-
торые представляют различные символы, например d, f,
G, Ю, я, 4, !, * и т. п. Такими символами могут быть все
знаки из кодовой таблицы ПЭВМ. Переменные типа int
и char можно использовать в одном выражении. В ТУРБО
СИ переменная типа char занимает 8 бит (1 байт);
5) unsigned (беззнаковый). В языке СИ можно объяв-
лять некоторые типы (char, short, int, long) беззнаковыми
с помощью модификатора unsigned (например, unsigned
char). Это значит, что соответствующие переменные не
будут иметь отрицательных значений. В результате они
могут принимать большие положительные значения, чем
переменные знаковых типов. Например, переменная типа
unsigned int может принимать значения от 0 до 65535
при том же размере, что и int (16 бит). В случае типа
int объявление вида unsigned int а; можно записать более
сжато: unsigned а;
6) float (вещественный). Этот тип задает значения, к
которым относятся вещественные числа, имеющие дроб-
ную часть, отделяемую точкой (например, —5.27, 0.0,
31.69 и т. п.). Вещественные числа могут быть записаны
также в форме с плавающей точкой, например —1.58е+2
(что равно —1.58Х Ю2). Число перед символом е называ-
ется мантиссой, а после символа е — порядком. В ТУРБО
СИ переменная типа float занимает 32 бита (4 байта).
Она может принимать значения в диапазоне ± (З.4е-38—
З.4е+38);
7) double (вещественный с двойной точностью). Этот
тип определяет вещественные переменные, занимающие
в два раза больше места, чем переменные типа float.
В ТУРБО СИ переменная типа double занимает 64 бита
(8 байт). Она может принимать значения в диапазоне
±(1.7е-308— 1.7е+308). Допускается тип long double.
192
Переменная этого типа имеет размер 80 бит (10 байт) и
может принимать значения от ЗЛЕ—4932 до 1.2Е4932;
8) enum (перечисляемый). Этот тип предназначен для
описания объектов из некоторого заданного множества,
например {SPRING, SUMMER, AUTUMN, WINTER).
Пусть идентификатор SEASONS может принимать одно из
приведенных выше значений. Запишем следующее объяв-
ление:
enum SEASONS (SPRING, SUMMER AUTUMN, WINTER};
Теперь можно объявить переменные перечисляемого типа.
Например:
enum SEASONS а, b, с;
Каждая из трех переменных (а, Ь, с) может принимать
одно из четырех значений: SPRING, SUMMER, AUTUMN,
WINTER;
9) signed (знаковый). Модификатор, противополож-
ный unsigned и указывающий на то, что описываемый
объект обязательно имеет знак. Объявление вида signed а;
эквивалентно объявлению signed int а;
10) const (константа). Этот модификатор не допускает
переопределения значений константы. Объявление вида
const а; воспринимается так же, как const int а;
11) vilatile (изменяемый объект). Этот модификатор
противоположен const. Он указывает, что объект может
быть изменен не только в программе, но и внешним
воздействием, таким, например, как прерывание со сторо-
ны другой программы. Как и выше, объявление vilatile а;
предполагает отношение к типу int;
12) pascal (объекты паскалевского типа). Действие
этого модификатора сводится к тому, что символ иденти-
фикатора преобразуется к верхнему регистру и не добав-
ляется символ подчеркивания (если идентификатор —
функция, данное правило распространяется и на переда-
ваемые параметры);
13) cdecl (объекты непаскалевского типа). Запрещает
назначение в системе программирования указанному объ-
екту паскалевского типа (отменяет назначение, заданное
единым общим указанием для всех идентификаторов);
14) interrupt (функция прерывания). Введен для ис-
пользования с векторами прерывания микропроцессора
Intel 8086/8088. Позволяет сделать некоторую функцию
программой обработки прерывания, вызываемой собствен-
ным вектором прерывания.
7 Скляров В. А
193
15) near, far, huge (модификаторы указателей на
данные). Указатель типа near имеет длину 16 бит
(2 байта) и задает смещение относительно регистра
сегмента данных микропроцессора (DS). Указатели типа
far и huge имеют длину 32 бита (4 байта) и задают как
адрес сегмента, так и смещение. Указатель типа huge в
отличие от far всегда поддерживает определяемый объект
в нормализованном виде. В результате обеспечиваются
естественность и правильность работы арифметических
операций и операторов отношения, но требуется допол-
нительное время для выполнения нормализации после
каждой операции;
16) void (отсутствие значения). Используется для
нейтрализации значения объекта (например, для опреде-
ления функции, не возвращающей никаких значений).
Многие модификаторы, такие, например, как pascal,
cdecl, interrupt, near, far, huge, не относятся к стан-
дартным понятиям языка СИ. Они специфичны для ПЭВМ
и ТУРБО систем программирования.
Рассмотрим, где в тексте программы объявляются
данные. Забегая вперед, можно сказать, что в языке
определены глобальные и локальные переменные. Гло-
бальные переменные объявляются вне любой из функций и,
следовательно, доступны для всех программных модулей.
Локальные переменные по отношению к функциям явля-
ются внутренними. Они начинают существовать при входе
в функцию и уничтожаются после выхода из нее. Ниже
показано, где объявляются в программе глобальные пере-
менные:
Объявление глобальных переменных
mai п ()
(
Тело программы
Функция
!
Тело функции
Покажем возможные места в программе для объявле-
ния локальных переменных:
Функция
Объявление локальных переменных, записанных в списке аргументов
Объявление локальных переменных
Тело функции
194
Рассмотрим примеры некоторых объявлений:
long a,b;
float с;
double d,e,f;
unsigned char g,r;
enum seasons]spring, summer, autumn, winter] i, j, k, 1;
Здесь i, j, k, 1 — переменные типа seasons, каждая из
которых может принимать одно из указанных четырех
значений. Эти значения являются целыми константами,
связанными с соответствующим идентификатором. В языке
принято, что spring=0, summer= 1 и каждая следующая
константа имеет значение на единицу больше, чем преды-
дущая. Можно присвоить константам определенные зна-
чения целого типа (идентификаторам, не имеющим их,
будут, как и ранее, назначены значения предыдущих кон-
стант, увеличенные на единицу). Например:
enum seasons {spring=2, summer=5, autumn, winter);
После этого spring=2, summer=5, autumn=6, winter=7.
Как и в языке ПАСКАЛЬ, текст в строке программы
может начинаться с любой позиции (пробелы, символы
табуляции и перехода на новую строку игнорируются).
Для большинства трансляторов в идентификаторах нельзя
использовать русские буквы. Это ограничение не распро-
страняется на комментарии и значения строковых кон-
стант.
Наряду с переменными в языке существуют следую-
щие виды констант:
1) вещественные;
2) целые;
3) длинные целые, в конце записи которых добавляется
буква L, например 361327L;
4) беззнаковые, в конце записи которых добавляется
буква U;
5) восьмеричные, в которых перед первой значащей
цифрой записывается нуль (0), например 071;
6) шестнадцатеричные, в которых перед первой знача-
щей цифрой записывается пара символов нуль—икс (ОХ),
например 0X1F2;
7) символьные — единственный символ, заключенный
в одинарные кавычки, например: ’q’, ’2’, и т. п. Символы,
не имеющие графического представления, можно записы-
вать, используя специальные комбинации, например \п
(для новой строки), \0 (nul, код которого 00000000). Эти
комбинации имеют вид двух символов, хотя фактически
это один символ. Точно так же можно представлять л'юбой
195
двоичный образ одного байта: ’\ЦЦЦ’, где ЦЦЦ — от
одной до трех восьмеричных цифр. Допускается и шест-
надцатеричное задание кодов символов, которое пред-
ставляется в виде ’\х2В’,’\х36’ и т. п.
8) строковые — последовательность из нуля или более
символов, заключенная в двойные кавычки, например:
’’кафедра ЭВМ Минского радиотехнического института”.
Кавычки не входят в строку, а лишь ограничивают ее.
Строка представляет массив из перечисленных элементов,
в конце которого помещается байт с символом\0. Таким
образом, число байтов, необходимых для хранения строки,
на единицу превышает число символов между двойными
кавычками;
9) константное выражение, состоящее из одних кон-
стант, которое вычисляется во время трансляции, напри-
мер a=60-f-30;.
6.2. ВВОД И ВЫВОД
Здесь рассматриваются четыре функции ввода-вывода:
printf, scanf, putchar и getchar. Первые две предназначены
для реализации форматного вывода и ввода данных.
Функция printf формально описывается следующим
образом:
printf (’’управляющая строка”, аргумент 1, аргумент 2,..).
Управляющая строка содержит объекты трех типов:
обычные символы, которые просто выводятся на экран
дисплея (копируются в стандартный выходной поток);
спецификации преобразования, каждая из которых вызы-
вает вывод на экран значения очередного аргумента
из последующего списка; управляющие символьные кон-
станты.
Каждая спецификация преобразования начинается со
знака % и заканчивается некоторым символом, задающим
преобразование. Между знаком % и символом преобразо-
вания могут встречаться: знак минус (—), указывающий,
что преобразованный параметр должен быть выровнен
влево в своем поле; строка цифр, задающая минималь-
ный размер поля; точка, отделяющая размер поля от
последующей строки цифр; строка цифр, задающая мак-
симальное число символов, которое нужно вывести, или же
число цифр, которое необходимо вывести справа от деся-
тичной точки в значениях типа float или double; символ
длины 1, указывающий, что аргумент имеет тип long.
196
Далее записывается один из следующих символов
преобразования:
d или i — значением аргумента является десятичное
целое число;
о — значением аргумента является восьмеричное це-
лое число;
х — значением аргумента является шестнадцатеричное
целое число;
с— значением аргумента является символ;
s — значением аргумента является строка символов.
Символы строки выводятся до тех пор, пока не встре-
тится символ конца строки (заключительный нуль — \0)
или же не будет выведено число символов, заданное
точностью;
е — значением аргумента является вещественное деся-
тичное число в экспоненциальном формате;
f — значением аргумента является вещественное деся-
тичное число с плавающей точкой;
g— используется как %е или %f и исключает вывод
незначащих нулей;
и — значением аргумента является беззнаковое целое
число;
р — значением аргумента является указатель (адрес).
Если после знака % записан не символ преобразова-
ния, то он выводится на экран. Функция printf использует
управляющую строку, чтобы определить, сколько всех ар-
гументов и каковы их типы. Аргументами могут быть
переменные, константы, выражения, вызовы функций.
Главное, чтобы их значения соответствовали заданной
спецификации. При наличии ошибок (например, в числе
аргументов или типе преобразования) результаты будут
неверными.
Среди управляющих символьных констант наиболее
часто используются следующие:
\а —для кратковременной подачи звукового сигнала;
\Ь — для перевода курсора влево на одну позицию;
\п — для перехода на новую строку;
\г — для возврата каретки (перевод курсора в начало
текущей строки);
\t — для горизонтальной табуляции;
\v—для вертикальной табуляции (в принтере).
Например, в результате записи инструкции вызова
функции:
printf (”\t3BM\n % dn”,i);
197
сначала будет выполнена горизонтальная табуляция (\t),
т. е. курсор сместится от края экрана, затем на экран
будет выведено слово ЭВМ, после этого курсор переводит-
ся в начало следующей строки (\п), будет выведено целое
значение i по формату d и окончательно курсор перейдет
в начало новой строки (\п).
Функция scanf формально описывается следующим
образом:
scanf (’’управляющая строка”, аргумент 1, аргумент 2,...);
Аргументы scanf должны быть указателями на соот-
ветствующие значения (перед именем переменной, записы-
вается символ &). Назначение указателей будет подробно
рассмотрено позже.
Управляющая строка содержит спецификации преоб-
разования и используется для установления количества и
типов аргументов. В нее могут включаться: пробелы, сим-
волы табуляции и переходы на новую строку (все они
игнорируются); спецификации преобразования, состоящие
из знака %, возможно, символа * запрещения присваи-
вания, возможно, числа, задающего максимальный размер
поля, и самого символа преобразования; обычные симво-
лы, кроме % (считается, что они должны совпадать с
очередными неизвестными символами во входном потоке).
В функции scanf допустимы те же символы преобра-
зования, что и для функции printf, за исключением g и е.
Так, например, если этим символом является d, то на входе
ожидается десятичное целое число. Перед символами d, о,
х, f может стоять буква 1. В первых трех случаях соот-
ветствующие переменные должны иметь тип long, а в по-
следнем — double. После выполнения функции scanf осу-
ществляется автоматический перевод курсора на следую-
щую строку. Например:
scanf (”%d%f%c%s”, &i, &j, &k, 1);^
Здесь i соответствует спецификации %d, j — %f, k — %c,
1 — %s. Предполагается, что строка 1 представляет собой
массив символов, объявленный, например, в виде:
char 1 [20];. Число 20 в квадратных скобках означает раз-
мер массива символов. В языке СИ имя массива является
указателем (адрес первого элемента в массиве), поэтому
знак & перед идентификатором 1 не нужен.
Вводимые числовые значения должны разделяться
пробелами. Если задать инструкцию:
scanf (”%d% * d%d”, &i, &j, );
198
и ввести три числа 5 7 10, то i получит значение 5, a j — 10.
Второе значение пропускается в связи с наличием символа
запрещения присваивания (*).
Самый простой механизм ввода—чтение по одному
символу из стандартного источника (с клавиатуры) с по-
мощью функции getchar. Инструкция вида c=getchar();
позволяет присвоить переменной с очередной вводимый
символ. Обращение putchar(c); выдает значение символа
с (этим значением является тоже символ) в стандартный
выходной поток (на экран дисплея). Переменная с должна
иметь тип int или char.
6.3. ОПЕРАТОРЫ И ВЫРАЖЕНИЯ
Выражения широко используются в программах на
языке СИ. Они состоят из операндов (переменные, кон-
станты и др.), соединенных знаками операций (сложение,
вычитание, умножение и др.). Порядок выполнения опе-
раторов при вычислении значения выражения определя-
ется их приоритетами и может регулироваться с помощью
круглых скобок.
Различают операции унарные, у которых один операнд,
и бинарные, у которых два операнда. В языке предусмотре-
ны две нетрадиционные операции ( + + ) для увеличения
на единицу и (--) для уменьшения на единицу значения
операнда (унарные операции инкремента и декремента).
Операции ++ и-------можно записывать как перед опе-
рандом, так и после него. В первом случае (4~+п или
-----п) значение операнда (п) изменяется перед его
использованием в соответствующем выражении; во втором
(п + + или п----) — после его использования. Рассмот-
рим две следующие строки программы:
а=Ь4-с + 4-;
а1 = Ы + ( + 4-с1);
Скобки во второй строке поставлены только для повыше-
ния наглядности (операция ++ имеет более высокий при-
оритет, чем +)- Предположим, что b=bl = 2, с=с1 = 4.
Тогда после выполнения операций: а=6, Ь=2, с=5, а 1 = 7,
Ы = 2, с1=5.
Широкое распространение находят также выражения с
еще одной нетрадиционной тернарной, или условной,
операцией?:. В формуле у=х?а:Ь; у=а, если х не равно
нулю, и у=Ь, если х равно нулю. Следующее выражение:
у= (а>Ь) ?а:Ь; позволяет присвоить переменной у значе-
199
ние большей переменной (а или Ь), т. е. у= max (а, Ь).
Еще одним отличием языка является то, что выражение
вида а=а+5; можно записывать и в другой форме:
а+=5;. Вместо знака + можно использовать символы
других бинарных операций (см. табл. 6.1).
Если в выражении появляются операнды различных
типов, они преобразуются к некоторому общему типу, при
этом к каждому арифметическому операнду применяется
такая последовательность правил:
1) char и short преобразуются в int, float — в double
(в языке СИ все действия с вещественными числами
производятся с двойной точностью). Далее выполняются
такие преобразования: char—int(co знаком); unsigned
char—тЦстарший байт всегда нулевой); signed char—
int (в знаковый разряд int передается знак из
char); short — int (знаковый или беззнаковый);
2) enum преобразуется в int;
3) если один из операндов двойной точности (double),
другие операнды тоже преобразуются к двойной точности
(double), и результат будет двойной точности (double);
4) в противном случае, если один из операндов имеет
тип long, другие операнды тоже преобразуются к long, и
результат будет long;
5) если один из операндов имеет тип unsigned, другие
операнды тоже преобразуются к типу unsigned, и резуль-
тат будет unsigned;
6) если все операнды имеют тип int, результат будет
int.
В табл. 6.1 перечислены различные операции языка
СИ. Их приоритеты для каждой группы одинаковы.
Чем большим преимуществом пользуется соответствую-
щая группа операций, тем выше она расположена в таб-
лице. Порядок выполнения определяет последовательность
реализации операций (слева направо или справа налево),
если отсутствуют круглые скобки и операции относятся к
одной группе.
Раньше уже упоминалось об указателях, т. е. о пере-
менных, содержащих адреса других переменных. Так как
указатель содержит адрес некоторого объекта, через него
можно обращаться к этому объекту.
Унарная операция & дает адрес переменной, поэтому
оператор у=&х; присваивает адрес х переменной у.
Операцию & можно применять только к переменным и
элементам массива; конструкции вида &(х + 7) или &28
недопустимы.
200
Объекты, состоящие из знака * и адреса (например,
*а), необходимо объявлять. Делается это, например, так:
int *а, *Ь, *с;
char *d;
Унарная операция * воспринимает свой операнд как
адрес некоторого объекта и использует этот адрес для
выборки содержимого, поэтому оператор z=*y; присваи-
вает z значение переменной, записанной по адресу у. Если
у = &х; z = *y; то z = x.
Объявление вида char *d; говорит о том, что значение,
записанное по адресу d, имеет тип char.
Указатели могут встречаться и в выражениях. Если
у — указатель на целое, т. е. имело место объявление
ind *у; то *у может появиться там же, где и любая другая
переменная, не являющаяся указателем. Таким образом,
вполне допустимы следующие выражения:
ту = 7;
= 5;
(tz)4- + ;
В последнем случае круглые скобки необходимы, так как
операции * и + + с одинаковым приоритетом выполняются
справа налево (см. табл. 6.1).
Указатели можно использовать как операнды в ариф-
метических операциях. Если у — указатель, унарная опе-
рация у + + ; увеличивает его значение; теперь оно яв-
ляется адресом следующего элемента. Указатели и целые
числа можно складывать. Конструкция у+п (у — указа-
тель, п — целое число) задает адрес n-го объекта, на
который указывает у. Это справедливо для любых объек-
тов (int, char, float и т. п.); транслятор будет масштаби-
ровать приращение адреса в соответствии с типом, опре-
деленным из соответствующего объявления.
Любой адрес можно проверить на равенство (= = )
или неравенство (1=) со специальным значением NULL,
которое позволяет определить ничего не адресующий
указатель.
Для организации циклов в языке СИ используются
три оператора: for, while и do-while. Первый из них фор-
мально записывается в таком виде:
for (выражение 1; выражение 2; выражение 3) тело цикла
Тело цикла составляет либо одна инструкция, либо
любое подмножество инструкций, заключенных в фигур-
ные скобки. В выражениях 1, 2, 3 фигурирует специальная
переменная, называемая управляющей. По ее значению
201
устанавливается необходимость повторения цикла либо
выхода из него. Каждое из трех выражений в скобках
имеет следующее назначение:
1) для присвоения начального значения управляющей
переменной;
2) для проверки выполнения условия продолжения
цикла;
3) для изменения значения управляющей переменной.
Таким образом, выражение 1 присваивает начальное
значение управляющей переменной, выражение 3 изменяет
его на каждом шаге, а выражение 2 проверяет, не достигло
ли оно граничного значения, устанавливающего необхо-
димость выхода из цикла. Любое из трех выражений
в цикле for может отсутствовать, однако точка с запятой
должна оставаться. Таким образом,
for(;;) {...)
бесконечный цикл, из которого выходят другими спо-
собами.
В языке СИ принято следующее правило: любое вы-
ражение с оператором присваивания, заключенное в круг-
лые скобки, имеет значение, равное присваиваемому. На-
пример, выражение (а=7+2) имеет значение 9. После
этого можно записать другое выражение, например ((а=
= 7 2) < 10), которое в данном случае будет всегда да-
вать истинное значение. Следующая конструкция:
((c=getchar ()) = = ’и’
позволяет вводить значение переменной с и давать
истинный результат только тогда, когда введенным зна-
чением является буква «и». В скобках можно записы-
вать и несколько формул, составляющих сложное выраже-
ние. Для этих целей используется операция запятая.
Формулы будут вычисляться слева направо, и все выра-
жение примет значение последней вычисленной „формулы.
Например, если имеются две переменные типа char, то
выражение
(х=у, y=getchar())
определяет следующие действия: значение переменной у
присваивается переменной х; вводится символ с клавиату-
ры и присваивается переменной у; все выражение получает
значение переменной у. Операция запятая находит наибо-
лее широкое применение для построения выражений цик-
ла for и позволяет параллельно изменять значения
нескольких управляющих переменных.
202
Допускаются вложенные конструкции, т. е. в теле
некоторого цикла могут встречаться другие операторы
for.
Оператор while формально записывается в таком виде:
while (выражение) тело цикла
Он является наиболее общим видом цикла и может исполь-
зоваться для замены двух оставшихся (последние созданы
для предоставления больших удобств пользователю).
Выражение в скобках может принимать ненулевое (ис-
тинное) или нулевое (ложное) значение. Если оно истинно,
выполняется тело цикла и выражение вычисляется снова.
Если выражение ложно, цикл while заканчивается.
Основным отличием между циклами while и do-while
является то, что тело в цикле do-while выполняется по
крайней мере один раз. Оператор do-while формально
записывается в таком виде:
do тело цикла while (выражение);
Тело цикла будет выполняться до тех пор, пока выра-
жение в скобках не примет ложное значение. Если оно
ложно при входе в цикл, его тело выполняется ровно один
раз.
Допускается вложенность одних циклов в другие, т. е.
в теле любого цикла могут появляться операторы for,
while и do-while.
В теле цикла могут использоваться новые операторы
break и continue. Первый из них обеспечивает немедлен-
ный выход из цикла, второй вызывает прекращение
очередной и начало следующей итерации.
Для организации условных и безусловных переходов
в программе в языке СИ используются операторы:
if — else, switch и goto. Первый из них записывается
в следующем формальном виде:
if (проверка условия) инструкция 1; else инструкция 2-
Если условие в скобках принимает истинное значение,
выполняется инструкция 1; если ложное,— инструкция 2.
Если вместо одной необходимо использовать несколько
инструкций, они, как и выше, заключаются в фигурные
скобки. В операторе if слово else может и отсутствовать.
В этом случае, если условие в скобках принимает истинное
значение, выполняется инструкция 1; если ложное, инст-
рукция 1 пропускается. Таким образом, инструкция 2
будет выполнена всегда.
203
В операторе if — else непосредственно после ключе-
вых слов if и else должны следовать другие инструкции.
Если хотя бы одна из них является инструкцией if, ее
называют вложенной. Согласно принятому в СИ согла-
шению, слово else всегда относится к ближайшему пред-
шествующему ему if.
Оператор switch позволяет выбрать одну из нескольких
альтернатив. Он записывается в следующем формальном
виде:
switch (выражение)
case константа 1: вариант 1; break;
case константа п—1: вариант п — 1: break;
default: вариант n; break;)
Здесь вычисляется значение целого выражения в скоб-
ках (его иногда называют селектором), и оно сравнивается
со всеми константами (константными выражениями). Все
константы должны быть различными. При совпадении
выполняется соответствующий вариант (одна или несколь-
ко инструкций). Вариант с зарезервированным словом
default реализуется, если ни один другой не подошел (сло-
во default может и отсутствовать). Если default отсутст-
вует, а все результаты сравнения отрицательны, ни один
вариант не выполняется. Для прекращения последующих
проверок после успешного выбора некоторого варианта
используется оператор break, обеспечивающий немед-
ленный выход из переключателя switch.
Рассмотрим правила выполнения безусловного перехо-
да, который можно представить в следующей форме:
goto метка;
Метка — это любой идентификатор. Оператор goto
указывает, что выполнение программы необходимо про-
должить, начиная с инструкции, перед которой записана
метка. В программе обязательно должна быть строка,
где указана метка, поставлено двоеточие и’ записана
инструкция, к которой должен выполниться переход.
Метку можно поставить перед любой инструкцией в той
функции, где находится соответствующий ей оператор
goto.
6.4. СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ
В программе на языке СИ можно использовать
структурированные типы данных. К ним относятся мас-
сивы, записи и файлы.
204
Массив состоит из нескольких элементов одного и то-
го же типа. Ко всему массиву целиком можно обращаться
по имени. Кроме того, можно выбирать любой элемент
массива. Для этого необходимо задать индекс, который
указывает его относительную позицию. Число элементов
массива назначается при его объявлении и в дальнейшем
не меняется. Если массив объявлен, к любому его эле-
менту можно обратиться следующим образом: указать
имя массива и индекс элемента в квадратных скобках.
Массивы объявляются так же, как и переменные:
int а [100];
char b [30];
float с [42];
В первой строке объявлен массив а из 100 элементов
целого типа: а [0], а[1],..., а [99] (индексация всегда
начинается с нуля). Во второй строке элементы массива
b имеют тип char, а в третьей — float.
Двухмерный массив представляется как одномерный,
элементы которого — тоже массивы. Например, объявле-
ние char а[10][20]; задает такой массив. По аналогии
можно установить и большее число измерений. Элементы
двухмерного массива хранятся по строкам, т. е. если
«проходить» по ним в порядке их расположения в памя-
ти, быстрее всего изменяется самый правый индекс. На-
пример, обращение к девятому элементу пятой строки
запишется так: а [5] [9].
В языке СИ существует сильная взаимосвязь между
указателями и массивами. Любое действие, которое
достигается индексированием массива, может быть выпол-
нено и с помощью указателей, причем быстрее.
Объявление int а [5]; определяет массив из пяти эле-
ментов: а [0], а [2], а [3], а [4], а [5]. Если объект *у объяв-
лен как int *у; то оператор у=&а[0]; присваивает пере-
менной у адрес элемента а [0]. Если переменная у указы-
вает на очередной элемент массива а, то у+1 указывает
на следующий элемент, причем здесь выполняется соответ-
ствующее масштабирование для приращения адреса
с учетом длины объекта (для типа int — 2 байта, long —
4 байта, double — 8 байт и т. п.). Поскольку само имя
массива есть адрес его нулевого элемента, инструкцию
у=&а [0]; можно записать и в другом виде: у=а;. Тогда
элемент a [i] можно представить как *(а~Н). С другой
стороны, если у — указатель, следующие две записи:
y[i] и *(у~Н) —эквивалентны. Между именем массива
205
и соответствующим указателем есть одно важное разли-
чие: указатель — это переменная, и у=а; или у++; —
допустимые операции; имя массива — константа, поэтому
конструкции вида а = у; а + + ; использовать нельзя, так
как значение константы постоянно и не может быть из-
менено.
Если указатели адресуют элементы одного массива,
то их можно сравнивать (отношения вида: (,), = = , !=
работают правильно). В то же время нельзя сравнивать
либо использовать в арифметических операциях указа-
тели на разные массивы (соответствующие соотношения
хотя и работают, но в большинстве случаев не имеют
смысла). Как и выше, любой адрес можно проверять на
равенство или неравенство со значением NULL. Указа-
тели на элементы одного массива можно также вычитать.
Тогда результатом будет число элементов массива, распо-
ложенных между уменьшаемым и вычитаемым объектами.
В языке СИ допускаются массивы указателей, которые
объявляются следующим образом: char*n [5];. Здесь
m [5] — массив, содержащий адреса элементов типа char.
Язык СИ не поддерживает отдельный строковый тип
данных, но он позволяет определить строки двумя раз-
личными способами. При первом способе используется
массив символов, при втором — указатель на первый сим-
вол массива. Объявление char а [10]; указывает компи-
лятору на необходимость резервирования места для
максимум 10 символов, из которых последний будет нуле-
вым (т. е. \0). Константа а содержит адрес ячейки памяти,
в которой помещено значение первого из 10 объектов типа
char. Процедуры, связанные с занесением конкретной стро-
ки в массив а, копируют ее по одному символу в область
памяти, на которую указывает константа а, до тех пор,
пока не будет скопирован нулевой символ, которым окан-
чивается строка. Когда выполняется функция типа printf
”%s”,a);, ей передается значение а, т. е. адрес первого
символа, на который указывает а. Если первый символ
нулевой, работа функции printf заканчивается; если не-
нулевой, она выводит его на экран, прибавляет к адресу
единицу и снова начинает проверку на нулевой символ.
Такая обработка позволяет снять ограничения на длину
строки (конечно, в пределах объявленной размерности):
строка может быть любой длины до тех пор, пока есть мес-
то в памяти, куда ее можно поместить.
Вторым способом определения строки является ис-
пользование указателя на символ. Объявление char *b;
206
задает переменную b, которая может содержать адрес ка-
кого-либо объекта. Однако в данном случае компилятор не
резервирует место для хранения символов и не инициали-
зирует переменную b конкретным значением. Когда
компилятор встречает инструкцию вида: Ь=”Ленинград”;,
он производит следующие действия: 1) как и в предыду-
щем случае, создает в каком-либо месте объектного мо-
дуля строку ’’Ленинград”, за которой следует нулевой
символ; 2) присваивает значение начального адреса этой
строки (адрес символа Л) переменной Ь. Функция printf
(”%s”,b); работает так же, как и в предыдущем случае,
осуществляя вывод символов до тех пор, пока не встре-
тится заключительный нуль.
Массив указателей можно инициализировать, т. е.
назначать его элементам конкретные адреса некоторых
заданных строк при объявлении. Переменные с адресами
могут образовывать некоторую иерархическую структуру
(быть многоуровневыми) типа указатель на указатель
(т. е. указатель содержит адрес другого указателя),
указатель на указатель на указатель и т. п.
Запись, или структура,— это объединение одного или
более объектов (переменных, массивов, указателей, дру-
гих записей и т. п.). Как и массив, она представляет
собой совокупность данных. Отличием является то, что к ее
элементам необходимо обращаться по имени и различные
элементы записи не обязательно должны принадлежать
одному типу.
Объявление записи осуществляется с помощью ключе-
вого слова struct, за которым идет ее тип и далее список
элементов, заключенных в фигурные скобки:
struct тип {тип элемента 1 имя элемента 1;
тип элемента п имя элемента п;};
Именем элемента может быть любой идентификатор.
В одной строке можно записывать через запятую несколь-
ко идентификаторов одного типа. Например:
struct date {int day;
mt month;
int year;};
Следом за фигурной скобкой, заканчивающей список
элементов, могут записываться переменные данного типа,
например struct date {...} а, b, с; (при этом выделяется
соответствующая память). Описание без последующего
списка не выделяет никакой памяти; оно просто задает
форму записи. Введенное имя типа позже можно исполь-
207
зовать для объявления записи, например struct date
days;. Теперь переменная days имеет тип date. При необ-
ходимости записи можно инициализировать, помещая за
объявлением список начальных значений элементов Раз-
решается вкладывать записи одна в другую, например:
struct man {char name [30], fan, [201
struct date bd;
int voz;)'
После этого разрешается объявить переменные, значе-
ния которых принадлежат введенному типу
struct man mans [100]
Здесь определен массив mans, состоящий из 100 записей
типа man.
В языке СИ разрешено использовать массивы записей.
Записи могут состоять из массивов и других записей.
Чтобы обратиться к отдельному элементу записи,
необходимо указать его имя, поставить точку и сразу за
ней написать имя нужного элемента. Например’
mans [i].voz=64;
mans[j].bd.day = 22;
mans[j].bd .year = 1976,
При работе с записями необходимо помнить, что тип
элемента определяется соответствующей строкой объявле-
ния в фигурных скобках. Например, mans имеет тип man,
year является целым числом и т. п. Поскольку каждый
элемент записи относится к определенному типу, его со-
ставное имя может появляться везде, где разрешено
использовать значения этого типа. Допускаются конструк-
ции вида mans[i] = mansfj]; где mansfi] и mans[j] — иденти-
фикаторы разных записей Другими словами, разрешается
присваивать одну запись другой по их именам.
Унарная операция & позволяет взять адрес записи.
Предположим, что задано объявление: „
struct date {int d,m у;) day;
Здесь day — запись типа date, включающая три элемента:
d, m, у. (Дрока вида struct date *db; устанавливает тот
факт, что db — это указатель на запись типа date. Теперь
для выбора элементов d.m.y записи необходимо использо-
вать конструкции (*db).d, (*db).m, (*db) .у. Действитель-
но, db — это адрес записи; *db — сама запись. Круглые
скобки здесь необходимы, так как точка имеет более высо-
кий, чем звездочка, приоритет. Для аналогичных целей
208
в языке СИ предусмотрена специальная операция —).
Она тоже выбирает элемент записи и позволяет предста-
вить рассмотренные выше конструкции в более простом виде:
db — >d, db —>m, db —>y.
Особую разновидность записей представляют поля и
смеси. Поле — это последовательность соседних двоичных
разрядов (битов) внутри одного целого значения. Оно
может иметь тип signed int либо unsigned int и занимать
от 1 до 16 бит. Поля размещаются в машинном слове
в направлении от младших разрядов к старшим. Напри-
мер, запись:
struct prim {int а:2; unsigned b:3; int:5;
int c:l; unsigned d:5;J i,j;
обеспечивает такое размещение: разряды машинного сло-
ва 0,1 отводятся для значения а; разряды 2—4 — для
значения Ь; разряды 5—9 не используются; разряд
10 — для значения с; разряды 11 —15 — для значения d.
Если бы последнее поле было задано так: unsigned
d:6;, оно размещалось бы не в первом слове, а в разрядах
0—5 второго слова.
В полях типа signed крайний левый бит является
знаковым. Например, такое поле шириной 1 бит
может только хранить значения — 1 и 0, так как
любая ненулевая величина будет интерпретироваться
как — 1.
Поля используются для упаковки значений нескольких
переменных в одно машинное слово с целью экономии
памяти. Они не могут быть массивами и не имеют адресов,
поэтому к ним нельзя применять унарную операцию &.
Смесь — это некоторая переменная, которая может
хранить (в разное время) объекты различных типа и раз-
мера. В результате появляется возможность работы в
одной и той же области памяти с данными различного
вида. Для описания смеси используется ключевое слово
union, а соответствующий синтаксис аналогичен записям.
Пусть задано объявление:
union г {int ir; float fr; char cr;) z;
Здесь ir имеет размер 2 байта, fr — 4 байта и cr — 1 байт.
Переменная z достаточно велика, чтобы сохранять самый
большой из трех приведенных типов. Таким образом, раз-
мер z — 4 байта. В один и тот же момент времени z может
иметь значение только одной из указанных переменных
(ir, fr, cr).
209
В языке СИ можно вводить имена для новых типов
данных с помощью зарезервированного слова typedef. На-
пример, описание
typedef int INTEGER;
делает слово INTEGER синонимом int. Теперь его можно
использовать для задания объявлений типа так же, как int.
В файлах размещаются данные, предназначенные для
длительного хранения. Каждому файлу присваивается
используемое при обращении к нему уникальное имя.
Прежде чем информация читается или записывается
в файл, он должен быть открыт. Это можно сделать,
например, с помощью библиотечной функции fopen. Она
берет внешнее представление — физическое имя файла
(например, Ь:р42.с) и связывает его с внутренним логи-
ческим именем, которое используется далее в программах.
Логическое имя — это указатель на требуемый файл (на
область памяти, где содержится информация о файле).
Указатель на файл необходимо объявлять, и делается это,
например, так:
FILE *Iopen(), *lst;
Здесь FILE — имя типа, описанное в стандартном опреде-
лении stdio.h; 1st — указатель на файл (логическое имя);
fopen — функция, выдающая указатель на файл. Обраще-
ние к функции fopen в программе производится так:
1st = fopen (физическое имя файла, вид использования файла);
Физическое имя файла может, например, быть: ”ргп” —
для устройства печати; ”b:zni.f” — для файла zni.f на
диске b и т. п. Вид использования — это например: ”w” —
запись; ”г” — чтение; ”а” — дополнение. Если файл
открывается для записи или дополнения, причем он еще не
существует, то он создается (если это можно сделать).
Открытие существующего файла для записи приводит
к уничтожению его старого содержимого. Попытка прочи-
тать несуществующий файл — ошибка (fopen выдает ука-
затель со значением NULL).
Для работы с файлами используются библиотечные
функции fprintf, fscanf, fputs. Они подобны соответствую-
щим функциям printf, scant, puts. Отличие состоит только
в том, что обмен данными идет не со стандартным устрой-
ством ввода-вывода, а с файлом, логическое имя которого
указано в виде первого параметра, например fscanf
(1st, ”%d”,&i); или fprintf (1st, ”%d”,i);. После окончания
210
работы с файлом он должен быть закрыт. Это делается
с помощью библиотечной функции fclose, например
fclose (1st)
6.5. ФУНКЦИИ
Программы на языке СИ обычно состоят из большого
числа отдельных функций (подпрограмм). Как правило,
они имеют небольшие размеры и могут находиться как
водном, так и в нескольких файлах. Связь между функция-
ми осуществляется через аргументы, возвращаемые значе-
ния и внешние переменные. Передача значения из вызван-
ной функции в вызвавшую происходит с помощью опера-
тора возврата, который записывается в следующем фор-
мальном виде:
return (выражение);
Таких операторов в подпрограмме может быть несколь-
ко, и тогда они фиксируют соответствующие точки выхода.
Вызвавшая функция может при необходимости игнориро-
вать возвращаемое значение. После слова return можно
ничего не записывать; в этом случае вызвавшей функции
никакого значения не передается. Управление передается
вызвавшей функции и в случае выхода «по концу» (послед-
няя закрывающаяся фигурная скобка).
В языке СИ аргументы функции передаются по значе-
нию, т. е. вызванная функция получает свою временную
копию каждого аргумента, а не его адрес. Это означает,
что функция не может изменять сам оригинальный аргу-
мент в вызвавшей ее программе. Ниже будет показано, как
снять это ограничение. Если же в качестве аргумента
функции используется имя массива, передается начало
массива (адрес начала массива), а сами элементы не
копируются. Функция может изменять элементы массива,
сдвигаясь (индексированием) от его начала.
В языке СИ сохраняются те же правила соответствия
параметров в вызове и в списке функции, что и в
ПАСКАЛе. Рассмотрим отличия, которые имеют место при
передаче подпрограмме адресов объектов. Пусть описание
функции начинается так: fun (к,с), а обращение к ней пред-
ставляется в виде a = fun(&b, &с);. В результате иденти-
фикатор к в вызванной функции будет указателем на зна-
чение b (адресом значения Ь), а идентификатор с в под-
программе — указателем на значение с в вызвавшей
функции.
211
Выше уже указывалось, что переменные передаются
функции по значению, поэтому нет прямого способа изме-
нить в вызванной функции некоторую переменную в вы-
звавшей функции. Однако это легко сделать, если переда-
вать в функцию не переменные, а их адреса.
Рассмотрим программу, включающую обращение к
функции izm:
(include (stdin.h>
»ain()
{ int a,b;
puts!"Введите значении a, b");
scanfl'Wtd" ,4a,4b);
printff"a = %d, b = %<i\n",a,b);
iz»!4a,4b); /> функция izi меняет местами два элемента;
ей передаются адреса этин здементпв >/
printfl"измененные значения: a=Xd; b=Sd",a,b);
/* вывод на экран измененных значений а н Ь */
)
(include 'iza.c'/t винчение файда izi.c с функцией iz« >/
Ниже дается текст функции izm:
iza|a,b) /« здементы а и b меняйся местами >/
int «а,*Ь;
f int с; /« а и b - указатедм, «а м *Ъ - значения, на
которие они указывают | значения а и b я
яызваяяей нрограиие >/
с=>а, »а:»Ь; «Цс;
}
Приведенная программа иллюстрирует использование
указателей в качестве аргументов функции izm. В нее
вводятся некоторые значения переменных а и Ь, и потом
в подпрограмме izm они меняются местами. Заметим, что
если в main а и b — переменные, то в izm —уже адреса,
а значения переменных по этим адресам будут соответ-
ственно *а и *Ь. Функция izm получает копию адресов
переменных а и Ь, меняет значения, записанные по этим
адресам, уничтожает полученные копии и перёДает управ-
ление в основную программу. Адреса &а и &Ь в основной
программе не изменились, а вот значения, на которые они
указывают, поменялись местами.
В файле, содержащем main, появилась новая строка:
# include ’’izm.c”
Эта команда, имеющая общий вид
# include "имя включаемого файла”
приводит к тому, что вместо нее подставляется содержи-
212
мое файла с указанным именем. При другом варианте
этой команды:
# include (имя включаемого файла)
поиск идет только в стандартных местах, определенных
системой программирования.
Если некоторые переменные, константы, массивы, запи-
си объявлены как глобальные, их не надо включать в спи-
сок параметров вызванной функции: она все равно получит
к ним доступ. Сами функции всегда глобальные (в языке
запрещено определять одни функции внутри других).
Если возвращаемое функцией значение имеет тип,
отличающийся от int или char, функцию надо объявлять.
Это делается для того, чтобы указать тип возвращаемого
функцией значения. В противном случае предполагается,
что это значение int. Объявление типа должно появиться
в первой строке с именем функции и в разделе объявлений
вызывающей программы.
В языке СИ различают четыре основных класса памя-
ти: внешнюю, автоматическую, статическую и регистро-
вую. Первая определена вне функций и, следовательно,
доступна для любой из них. Область действия внешней
переменной простирается от точки во входном файле, где
она объявлена, до конца файла. Если на внешнюю пере-
менную нужно ссылаться до ее объявления или она опреде-
лена в другом входном файле, вступает в силу описание
extern (в файле с вызываемой функцией внешние пере-
менные будут доступны после их описания с помощью
зарезервированного слова extern).
Автоматические переменные по отношению к функциям
являются внутренними, или локальными. Они начинают
существовать при входе в функцию и уничтожаются при
выходе из нее (для них можно использовать либо не
использовать дополнительное зарезервированное слово
auto).
Значения статических переменных помещаются в тре-
тий класс памяти. Они объявляются с помощью заре-
зервированного слова static и могут в свою очередь быть
внутренними (локальными) или внешними (глобальны-
ми). Внутренние статические переменные, как и автома-
тические, локальны по отношению к отдельной функции.
Однако они продолжают существовать, а не возникают
и уничтожаются при каждом ее вызове. Другими словами,
они являются собственной постоянной памятью для функ-
ции. Внешние статические переменные доступны внутри
213
оставшейся части файла, после того как они в нем объявле-
ны, однако в других файлах они не известны.
Регистровые переменные относятся к четвертому клас-
су. Зарезервированное слово register указывает на то, что
переменная, о которой идет речь, будет интенсивно исполь-
зоваться. Если это возможно, значения таких переменных
помещаются во внутренние регистры процессора, что мо-
жет привести к более быстрой и короткой программе. Для
регистровых переменных нельзя взять адрес; они могут
быть только автоматическими с допустимыми типами int
или char.
Выше уже говорилось об инициализации, т. е. о присво-
ении различным объектам начальных значений. Если
явная инициализация отсутствует, гарантируется, что
внешние и статические переменные будут иметь значение
нуль, а автоматические и регистровые — неопределенное
значение. Переменные можно инициализировать при их
объявлении, если следом за именем поставить знак равен-
ства и константное выражение. Массивы можно инициали-
зировать, поместив в объявлении список требуемых значе-
нии, заключенных в фигурные скобки и разделенных
запятыми. Для символьных массивов существует спе-
циальный способ инициализации: вместо записи с по-
мощью скобок и запятых можно использовать строку
такого вида:
char s [ ] = ’Ульяновский политехнический институт”;
Если размер массива любого типа пропущен, транслятор
определяет его длину, подсчитывая инициализирующие
значения.
Вернемся к объявлению функций. Его можно осуще-
ствить двумя способами. При первом способе оно выглядит
так:
тип функция ( ); »,
Здесь определено имя — функция и тип возвращаемого ею
значения — тип. Поскольку в приведенной выше строке
параметров нет, нельзя осуществить проверку правиль-
ности их указания.
При втором способе используется конструкция, назы-
ваемая прототипом функции. В соответствующем объявле-
нии будет дана информация о параметрах. Она представ-
ляется в следующем виде:
тип функция (параметр 1, параметр 2,...);
214
Для каждого параметра можно указать только его тип
(например: тип функция (int, float,...);), а можно дать и
его имя (тип функциями! a, float b,...);). Если функция
имеет переменное число параметров, вместо последнего из
них указывается многоточие. Второй способ является бо-
лее предпочтительным, так как он позволяет компилятору
отслеживать число и тип параметров при вызове функции.
Выше уже говорилось, что объявление типа должно
появляться и в первой строке с именем функции, после
которого идет текст, составляющий ее тело. Здесь также
можно использовать два способа. Для первого из них
соответствующая строка будет такой:
тип функция (имя переменной 1, имя переменной 2,...)
При использовании второго способа эта строка выгля-
дит так же, как и прототип функции, но есть одно исключе-
ние: в конце строки не нужна точка с запятой, тогда как
после прототипа ее наличие обязательно.
В языке СИ есть особый тип void, который использует-
ся для явного описания функций, не возвращающих значе-
ний. Пустой список параметров можно тоже определить
словом void. Строка вида
(тип) выражение;
позволяет преобразовать выражение к типу, заданному
в круглых скобках. Например:
а= (int)b-(-int(c);
В языке СИ сама функция не может быть значением
переменной, но можно определить указатель на функцию.
С ним можно обращаться, как с переменной: передавать
его другим функциям, помещать в массивы и т. п. Объявле-
ние вида
int (42) ( );
говорит о том, что f2 — это указатель на функцию, воз-
вращающую целое значение. Первая пара скобок необхо-
дима: без них int *f2( ); означало бы, что f2— функция,
возвращающая указатель на целое значение. После объ-
явления указателя на функцию в программе можно
использовать объекты: *f2 — сама функция; f2 — указа-
тель на функцию. Здесь, как и для массивов, имя функ-
ции — это указатель.
В программы на языке СИ можно передавать неко-
торые аргументы или параметры из командной строки ОС.
Когда в начале вычислений производится обращение к
215
main, ей передаются два параметра. Первый из них имеет
имя argc и определяет число командных аргументов при
обращении к программе. Второй, с именем argv, представ-
ляет собой указатель на массив символьных строк, содер-
жащих эти аргументы (в одной строке — один аргумент).
Предположим, что на диске В есть некоторая программа
PROG.EXE. Обратимся к ней следующим образом:
В) PROG Новосибирск Ульяновск Минск(ВВОД)
Тогда argv[0] — это указатель на PROG; argv[l] — ука-
затель на строку Новосибирск и т. п. На первый факти-
ческий аргумент указывает argv[l], а на последний—
argv[3]. Если argc = l, то после имени программы в ко-
мандной строке параметров нет (в приведенном примере
argc =4).
Как и в ПАСКАЛе, в языке СИ допустимы рекурсивные
вызовы функций. Поскольку здесь функции являются
всегда глобальными объектами, взаимно рекурсивные под-
программы не требуют никаких дополнительных объ-
явлений.
6.6. МАКРОПРОЦЕССОР
Транслятор СИ имеет встроенное средство, расширяю-
щее возможности языка и называемое макропроцессором
или препроцессором. Он выполняет подстановки для мак-
ровызовов, проводит условную трансляцию и подключает
указанные файлы. Для макропроцессора предназначены
строки программы, начинающиеся с символа #. Его ко-
манда # include уже была использована ранее. Она имеет
вид
# include "имя файла”
В конце команд макропроцессора не ставится точка
с запятой. Действие этой команды приводит’-к включению
в программу файла с заданным именем, который нахо-
дится в указанном для системы программирования катало-
ге. При другом варианте команды:
=4f=include (имя файла)
поиск идет только в стандартных местах, определенных
в системе программирования. Команды # include могут
«вкладываться» одна в другую.
Строка
Ф= define идентификатор подстановка
216
вызывает замену в последующем тексте названного иден-
тификатора текстом подстановки. Если команда имеет вид
define идентификатор (идентификатор,..., идентификатор) подстановка
причем между первым идентификатором и открывающейся
круглой скобкой нет пробела, то это определение макро-
подстановки с аргументами. Ее использование рассматри-
вается далее на примерах. При наличии длинных опре-
делений в подстановке, продолжающихся в следующей
строке, в конце очередной строки с продолжением ставится
символ\.
Опишем другие команды макропроцессора.
Первая из них:
=H=if константное выражение
проверяет, будет ли отличаться от нуля выражение, со-
ставленное из констант.
Вторая:
=#=ifndef идентификатор
устанавливает, определен ли в данный момент указанный
идентификатор, т. е. входил ли он в команду вида 4# define.
Строка вида:
=#=ifdef идентификатор
проверяет, не определен ли в данный момент указанный
идентификатор.
За любой из этих команд может следовать произволь-
ное число строк текста, возможно, содержащих инструк-
цию #else и заканчивающихся строкой 4#endif. Если
проверяемое условие истинно, игнорируются все строки
между 4#else и 4#endif; если ложно, игнорируются строки
между проверкой и #else (если последнего слова нет, то
#endif), т. е. здесь имеет место полная аналогия с опера-
тором if — else, за исключением того, что добавляется
строка 4#er|dif.
Приведенные инструкции могут «вкладываться» одна в
другую.
Команда вида:
#undef идентификатор
приводит к тому, что указанный идентификатор начинает
считаться не определенным, т. е. не подлежащим замене.
В макроопределение можно заносить вместе два объек-
та, разделенных знаками ##. Например:
# define рг(х.у) (х# #у)
217
После этого рг (а,3) вызовет подстановку аЗ.
Символ #, помещаемый перед макроаргументом, ука-
зывает на преобразование его в строку. Например, после
директивы
#define prim(var) printf (ф var”= % d ”,var)
следующий фрагмент текста программы:
year = 1988;
prim (yeaг);
преобразуется так:
year= 1988;
printf (’'year”" = %d”, year);
Для компилятора ТУРБО СИ есть еще одно отличие.
Здесь не выполняется подстановка макроаргументов
внутри строк и символьных констант. Допускается исполь-
зование оператора sizeof (определение размера объекта)
в выражении для макропроцессора.
Рассмотрим примеры. Строка
Ф define begin {
дает возможность последующей замены в тексте программы открываю-
щейся фигурной скобки ({) словом begin.
После появления строки
Ф define read(valr) scanf(”%d,",&valr)
инструкция read(i); воспринимается так же, как scanf(”%d”,&i);. Здесь
valr — аргумент и выполнена макроподстановка с аргументом.
Три следующие команды:
Ф if def write
4pundef write
Ф endif
проверяют, определен ли идентификатор write (т. е. была ли команда
Ф define write...), и если это так, то write начинает считаться не
определенным, т. е. не подлежащим замене. Другие строки:
ф!йЩеГ write
Ф define write fprintf *:
Ф endif
проверяют, не определен ли идентификатор write, и если это так, то
определяется идентификатор write вместо идентификатора fprintf. .
6.7. ПРОГРАММИРОВАНИЕ НИЗКОГО УРОВНЯ
В языке СИ применяются специальные объекты, назы-
ваемые псевдопеременными. Они используются для обра-
щения к ресурсам микропроцессора Intel 8086. Полный
список псевдопеременных включает 21 элемент: АХ,
218
BX,_CX,_DX,_CS,_DS,_SS,_ES, SP, BP, DI,
_SI,_AL,_AH,_BL,_BH,_CL,__CH,_DL,_DH,_
FLAGS. Первые 12 и 21 -й имеют тип unsigned int, а остав-
шиеся 8 — unsigned char. Они определенным образом свя-
заны с регистрами микропроцессора (см. рис. 1.1). При-
своение значения какой-либо переменной, например_АХ,
вызывает занесение этого значения в регистр АХ. Вывод
значения переменной, например_ВХ, эквивалентен выво-
ду значения из регистра ВХ. Таким образом, псевдопере-
менные — это идентификаторы, соответствующие данным
регистрам. Они могут трактоваться как глобальные объ-
екты указанного типа.
В ТУРБО СИ определяются (в stdio.h) и открываются
системные файлы: stdin, stdout, stderr, stdprn и stdaux.
О них уже говорилось в гл. 3. Таким образом, инструкция
fprintf(stdprn, ’’Значение переменной i равно: %,” i);
приведет к выводу текста ’’значение переменной i равно:”
и целого значения i на принтер.
Для данных, имеющих тип near, существуют 4 новых
указателя:__cs,_ds,_ss и___es. Они специальным обра-
зом связаны с соответствующими сегментными регистра-
ми. Например, если объявить:
char _ss *а;
то переменная а будет содержать 16-разрядное смещение
в стековом регистре микропроцессора (SS).
В языке используется еще одно ключевое слово asm для
введения команд ассемблера в следующей форме:
asm (допустимая команда микропроцессора 8086) (операнды (можно
ссылаться на СИ константы, переменные и метки)) ('.(точка с запятой)
или новая строка—один из признаков конца оператора asm)
Программы с ассемблерными командами должны ком-
пилироваться с помощью автономного компилятора
ТСС.EXE (об этом см. в гл. 9). Вместе с ними должен
быть еще и транслятор с языка ассемблера (например,
TASM.EXE или MASM.EXE). В тексте программы следует
записать директиву 4#pragma inline, которая указывает
на то, что имеются ассемблерные строки. Перечислим все
действия, которые необходимо выполнить:
1) с помощью редактора интегрированной среды
ТУРБО СИ создать программный файл, дать ему имя
(например, С__ASM.С) и сохранить на диске;
2) выйти в среду ОС;
3) поместить в один каталог все необходимые файлы.
219
По крайней мере в нем должны быть ТСС.ЕХЕ,
TLINK.EXE (см. гл. 9), TASM.EXE или MASM.EXE
(см. гл. 8). Сделать этот каталог текущим (пусть он будет,
например, С);
4) выполнить команду
С>ТСС С ASM<Bвод>
В результате будет получен модуль С ASM.ЕХЕ. Если
используется компилятор MASM.EXE, aTCC.EXE требует
TASM.EXE, то следует переименовать MASM.EXE в
TASM.EXE.
Если в программу не включена директива 4#Pragma,
можно обойтись и без нее, но надо выполнить команду
с > ТСС —В C ASM( В ВОД >
Если перечисленные выше программы находятся в раз-
ных каталогах, нужно указывать соответствующие марш-
руты.
Рассмотрим пример простейшей программы, выполняющей сумми-
рование двух целых чисел. Ввод и вывод производятся в СИ, а сложе-
ние — в ассемблере:
Upragna inline /« эта директива указывает кохпидятору на
то, что в программе есть ассеибдериые строки »/
void »ain()
( int i.j.s;
puts!'Введите зиачеиия i и Г);
scanf("ИМ',ii,1 j); /« ввод значений i и j «/
asa pash ах /« значение регистров ах и Ьх »/
asa pash Ьх /» помечается в стек «/
аза bov ах,i /« в ах заносится введенное значение i «/
аза bov Ьх,] /t в Ьх заносится введенное значение j »/
аза add ах,Ьх /« сумма ах и Ьх сохраняется в ах »/
аза ш 5,ах /* содержимое ах передается в s »/
аза pop Ьх /« из стека восстанавливаются »/
аза pop ах /« значения регистров ах и Ьх »/
printffi t j ; Sd\n",s); /« вывод резумьтата */
)
После запуска программы на выполнение она запрашивает значе-
ния i и j. После ввода их будет выдана сумма.
6.8. СТИЛЬ ПРОГРАММИРОВАНИЯ
При написании программ на языке СИ могут быть
допущены ошибки. Чтобы минимизировать их число, про-
анализируем некоторые часто встречающиеся упущения
и дадим соответствующие рекомендации, касающиеся сти-
ля программирования.
Наиболее обширную группу составляют ошибки в про-
220
граммах, манипулирующих указателями. Например:
int *а;
*а = 25;
Здесь указателю а предварительно не назначено значение,
и он содержит какой-то случайный адрес. По этому
случайному адресу может быть записана другая информа-
ция, которая будет испорчена.
Напомним о возможных способах представления строк
в памяти ПЭВМ. Их можно объявлять в виде соответ-
ствующего массива типа char либо как указатель на тип
char. В первом случае будет выделена требуемая область
памяти, во втором — нет.
Рассмотрим следующую программу:
linclude (stdin.h>
aainf)
t char «мае;
char nna«e[15];
puts("\nKait Вас зовут?");
scant ("Is",naae);
anaae = "Здравствуй,
printf("XsXs\n",anaie,naie);
В ней две ошибки. Первая связана с оператором
scanf(”%s”, name); Действительно, программа не выде-
лила никакой памяти для пате. Введенное имя сохраняет-
ся по любому случайному адресу. По результатам компи-
ляции программы будет выдано предупреждение, но не
ошибка. Вторая оплошность связана с оператором гппа-
те = ’’Здравствуй, Компилятор думает, что имеет место
попытка изменения значения шпате на адрес строки-
константы ’’Здравствуй, ”. Но этого делать нельзя. Выше
уже говорилось, что имя массива (в примере — шпате)
есть константа, которая не может быть изменена. Здесь
компилятор выдаст сообщение об ошибке. Самый простой
способ устранения ошибок сводится к следующим изме-
нениям:
linclude <stdio,h>
saint)
[ char naae[15);
char tanaae;
puts('\nlta« Вас зовут?");
scanffUs",naae);
anaae : "Здравствуй,
printf(“%5%s\n".anaae,naae);
221
Второй способ позволяет не изменять введенные опи-
сания:
#include <stdio.h>
einclude (alloc.h>
nain()
{ char <naae;
char anaae[15);
puts("\nKaic Вас зовут?');
na»e - (char*)ulloc(20);
scanf("Us",naee);
strcpy(апаше,"Здравствуй,
printf("%s%s\n",ппаяе,папе);
)
Функция malloc (см. гл. 10) выделяет 20 байт свободной
памяти и заносит в шпате адрес ее начала. Функция
strcpy копирует знак за знаком символы константы
’’Здравствуй, ” в массив шпате. Файл alloc.h содержит
требуемые описания для библиотечного модуля.
Часто возникают ошибки при использовании функции
scanf. Напоминаем еще раз, что она требует, чтобы пере-
давали адреса вместо значений (перед именем переменной
записывается унарный оператор &).
Перечислим другие возможные оплошности:
1) нельзя путать оператор присваивания ( = ) и отно-
шения равно ( = = );
2) нельзя опускать зарезервированное слово break в
операторах switch;
3) не следует забывать, что первый индекс массива —
нуль, а не единица. Если задано объявление: int а [3];, то
резервируется память для элементов массива: а [0], а [ 1 ] и
а [2];
4) нужно помнить, что аргументы передаются в вызы-
ваемую функцию по значению. Эта функция не может
изменить сам оригинальный аргумент в вызвавшей про-
грамме.
Оговорим некоторые приемы современног® стиля про-
граммирования, допускающего реализацию в языке СИ.
1. Использование прототипов функций и полных описа-
ний функций. Это дает дополнительную информацию для
компилятора и позволяет выявить многие возможные
ошибки. Транслятор СИ гарантирует соответствие опре-
делений и описаний.
2. Использование описания enum. В результате мно-
жество строк вида:
4|= define mon 0
# define tues 1
222
# define wed 2
# define thur 3
# define fri 4
можно представить так:
typedef enum (mon, tues, wed, thur, fri) work;
Если далее объявить: work а;, то переменной а можно
назначать значения от шоп до fri (вместо констант от О
до 4).
3. Введение собственных привычных и легко понимае-
мых типов данных с помощью зарезервированного слова
typedef. Например, описанием typedef char (*FUN)();
вводится новый тип FUN для указателя на функцию,
выдающую символьное значение. Теперь его можно
использовать, например, так: FUN fn, fm; вместо объявле-
ния: char (*fn)( ), (*fm)( );.
4. Любую функцию, не возвращающую значения, сле-
дует объявлять типом void.
Большое число полезных примеров собрано в книгах
[15, 17].
7. ЯЗЫК ПРОЛОГ
7.1. ПРОГРАММЫ И ДАННЫЕ
ПРОЛОГ — язык логического программирования,
предназначенный для представления и использования зна-
ний о некоторой предметной области. Первый интерпре-
татор ПРОЛОГа был создан в Марселе в 1973 г. Про-
грамма на этом языке состоит из некоторого множества
отношений, а ее выполнение сводится к выводу нового от-
ношения на основании заданных. Рассмотренные выше
языки относятся к процедурному типу. Это означает, что
программист должен указать все шаги вычислений, кото-
рые ведут к решению поставленной задачи. В ПРОЛОГе
реализован декларативный подход, при котором достаточ-
но описать задачу с помощью правил и утверждений отно-
сительно заданных объектов. Если это описание является
достаточно точным, то ЭВМ может самостоятельно найти
требуемое решение.
В программах на ПРОЛОГе существует три типа ко-
манд: факт, правило вывода и цель. Факт соответствует
описанию какого-либо простого утверждения, выражаю-
щего истину, например ’’Минск (столица_БССР)”. Здесь
устанавливается, что Минск является столицей БССР.
Правило вывода описывает утверждения, зависящие от
условий, например ’’взять зонтик: —идет дождь”. Здесь
два символа: двоеточие и тире (:—) обозначают условие
’’если” (if). Другой пример: ’’очередь (X):—дефицит
(X)”. Здесь X— переменная (переменные в ПРОЛОГе на-
чинаются с прописной буквы и этим отличаются от кон-
стант). Соответствующее правило говорит о том, что если
объект (товар) X — дефицит, то за ним стоит очередь.
Можно записать и другое (уточняющее) правило: ’’оче-
редь (X): — есть в магазине (X), дефицит (X)”. Запятая
воспринимается как связка ”и” (and), поэтому данное
правило можно записать и в другом виде: ’’очередь (X) if
есть__в__магазине (X) and дефицит (X)”.
224
Посредством указания цели ставится интересующий
нас вопрос. Например:
Минск (столица_БССР),
очередь (X).
В первом случае будет выдан ответ true (истина);
во втором — все виды объектов (товаров), за которыми
стоит очередь (чтобы этот список не был бесконечным,
требуется наложение дополнительных условий, например
предварительное перечисление конечного перечня товаров
определенной группы). Если поставить вопрос следующим
образом:
Минск (столица_США),
то будет дан ответ false (ложь).
На все поставленные вопросы ПРОЛОГ пытается от-
ветить с помощью фактов, хранимых в базе данных, и пра-
вил вывода. Он решает задачу по методике сверху вниз
и слева направо. Это означает, что сначала анализируется
цель и ведется поиск такого факта или правила вывода,
с помощью которого она может быть достигнута. При на-
хождении такого факта после соответствующей подста-
новки переменных ПРОЛОГ переходит к решению следую-
щей цели при условии, что предыдущая была доказана.
Если некоторая цель последняя, доказательство заканчи-
вается. При отсутствии нужных фактов, но наличии пра-
вила вывода, которое могло быть применено, цель заме-
няется условием этого правила с соответствующей под-
становкой переменных. Теперь условием выполнения цели
становится доказательство условия правила вывода. Про-
цесс нахождения соответствия между целью и фактом или
правилом называется унификацией. В ходе унификации
ПРОЛОГ ищет все альтернативные решения.
Принципы построения программ на этом языке рас-
смотрим на примере инструментальной системы ТУРБО
ПРОЛОГ. Программа ТУРБО ПРОЛОГа включает опре-
деленные разделы, не все из которых являются обяза-
тельными:
domains (домены) — раздел объявлений;
global domains (глобальные домены);
database (база данных);
predicates (предикаты) —отношения между объ-
ектами;
global predicates (глобальные предикаты);
goal (цель);
8 Скляров В А.
225
clauses (предложения, включающие факты и пра-
вила) .
В программе по крайней мере должны быть разделы
predicates и clauses. Идентификатор global (глобаль-
ный) указывает на то, что последующие объекты отно-
сятся к нескольким программным модулям.
Рассмотрим возможную структуру программы на языке
ПРОЛОГ:
domains
... операторы доменов ...
predicates
... операторы предикатов ...
goal
... цель ...
clauses
... факты и правила ...
Раздел domains напоминает объявление данных в
языках ПАСКАЛЬ и СИ. Существуют следующие типы
доменов: char (символьный), integer (целый), real (ве-
щественный), string (строковый), symbol (для цепочки из
букв, цифр и символов подчеркивания с первой строчной
буквой либо цепочки знаков в двойных кавычках), file
(файловый). Для наименования объектов в ТУРБО ПРО-
ЛОГе нельзя использовать русские буквы (за исключением
тех, которые записаны в двойных кавычках).
Как и для рассмотренных выше языков, алфавит ПРО-
ЛОГа включает прописные и строчные буквы, цифры и спе-
циальные знаки. Специальные символы (каждый в отдель-
ности либо в комбинации друг с другом) позволяют за-
давать операторы и знаки операций. Перечислим часто
используемые в программах специальные символы либо их
комбинации:
/*, —запись комментариев, например: /*г. Улья-
новск*/;
:— или if — оператор ’’если”; *’
, или and — связка И;
; или or — связка ИЛИ;
” — задание символьной информации, например: ’’го-
род Новосибирск”;
'—задание символьных констант, например: 'q';
_____— начинает имя анонимной (безымянной) перемен-
ной;
[’] —для обрамления элементов списка (см. § 7.3);
* — для объявления списка (см. § 7.3), например:
list = integer * (здесь объявлен список list целых чисел);
226
I—для разделения заголовка и хвостовой части
списка.
Отдельные из перечисленных символов могут исполь-
зоваться и в другом смысле. Соответствующие правила
видны из контекста. Порядок их применения будет показан
далее на примерах. Символы, применяемые в качестве
знаков арифметических и других операций, будут опи-
саны в § 7.4.
По отношению к именам объектов (идентификаторов)
в ПРОЛОГе используются следующие правила:
1) имя может включать латинские буквы, цифры
и символ подчеркивания, причем первым символом не
должна быть цифра;
2) имена символических констант должны начинаться
со строчной буквы;
3) имена переменных должны начинаться с пропис-
ной буквы или с символа подчеркивания;
4) в имени можно одновременно использовать и строч-
ные, и прописные буквы.
Ра ссмотрим пример программы на языке ПРОЛОГ. На рис. 7.1
показан ориентированный граф, содержащий вершины a, b, с, d, е, 1
Рис. 7.1. Ориентированный граф
и дуги (линии со стрелками). В программе, текст которой приведен
ниже, устанавливается: есть ли дуга между вершинами; имеет ли она
стрелки на обоих концах; образуют ли три следующие друг за другом
дуги треугольники:
doaains
point;syibol
/» объект point имеет тип syibol »/
predicates /« вводятся три отношения: arc., line, и tr »/
arc_(point,point)
linejpoint,point)
tr(point,point,point)
claases
/« описание суиествуцит путей (дуг) »/
227
агс_(а, с).
arcjb.c).
arcjc.d).
arcjd.a).-
arc_(d,e).
arc_(c,b).
arcja.f).
/< ycioBHe того, что аиниг пиеег стреаки на обоих концах «/
line_(A,B) if arc_(A,B) and агс_(В,А).
/» усювие мго, что три схедувцкх друг за другом дуги
образует треугольник «/
tr(X,Y,Z) if arc_(X,Y) and arc_(Y,Z) and arc_(Z,X).
В разделе domains объявлен один объект point типа symbol.
В разделе predicates определены три отношения: arc________________, line___ и tr.
Их аргументами являются объекты point. В разделе clauses определены
факты, например аге________(а, с) — существует дуга из вершины а в вер-
шину с, и правила, например tr(X, Y, Z) И arc___________(X, Y) and arc_____(Y, Z)
and arc____(Z, X) — дуги между вершинами X, Y, Z образуют треуголь-
ник, если есть дуга из X в Y, из Y в Z и из Z в X.
После запуска программы в среде ТУРБО ПРОЛОГ на выпол-
нение в окне Dialog экрана появится строка Goal :. Введем, например,
line (Е, Т). В результате получим: Е = Ь, Т = с, Е = с, Т = Ь 2 Solutions,
т. е. найдено два решения. Точно так же можно ставить вопросы для
отношений аге______ и tr. Например, если ввести: аге_________(а,Ь), результатом
будет false (ложь), а если ввести arc______________(a,f),— true (истина). На
вопрос arc_____(F,c) ПРОЛОГ выдаст два решения: F=a и F=b.
Приведенную программу можно переписать так, что она будет
содержать всего лишь два раздела: predicates и clauses:
predicates
arc_(sy«bol, symbol)
linej syebo 1, symbol)
tг(зушЬо1,synbo1,symbo1)
clauses
arcja.c).
arc_(b,c).
arcjc.d),
arc_(d,a).
arcjd.e).
arc_(c,b).
arc_(a,f).
lineJA.B) if arc_(A,B) and arc_(B,A).
tr(X,Y,Z) if arc_(X,Y) and arcJY,Z) and arcJZ.X).
Если при компиляции программы необходимо получить
и сохранить на диске загрузочный модуль (*.ЕХЕ файл),
то цель (goal) должна быть включена в текст программы.
В языке ПРОЛОГ есть специальный элемент cut,
который предотвращает возврат в предыдущее состояние
для поиска следующего решения. Он записывается в про-
грамме в виде восклицательного знака (!).
Рассмотрим пример:
228
/« в этом примере демонстрируетси использование
операции ent (!) «/
predicates /« вводятеи три отиоиении: arc., line, и tr «/
arcjsyabol, syabol)
line_(syabol,syabol)
tr(sysbol,syabo1,syibol)
/» здесь оператор goal введем в текст програиин «/
goal tr(Q,E,E), Hrite(Q,E,E),nl.
clauses
/« описание существующих путей (дуг) «/
arc_(a,c).
arc.(b.c).
arc_(c,d).
arc_(d,a).
arc_(d,e).
arcjc.b).
arc_(a,f).
arc.(b.a). /« ata строка добавлена «/
/« условие того, ио линия имеет стрелки иа обоих концах
(требуетси найти юбое одно реиеиие) «/
Iine_(X,B) if arc.(M) and агс_(В,Л) and !.
/« условие того, но три следующих друг за другом дуги
образуют треугояьиик (требуетси найти любое одно
реиеиие) «/
tr(X,K,Z) if arcJXJ) and arc_(f,Z) and arc_(Z,X) and !.
Здесь цель (goal) введена в текст программы. Предикат write обеспе-
чивает вывод на экран дисплея полученных значений переменных
Q, W и Е. Он будет описан в следующем параграфе. Предикат п! обес-
печивает возврат каретки и перевод строки (перемещение курсора
на экране дисплея в начало следующей строки). После запуска про-
граммы на выполнение в среде MS-DOS на экране появится одно
решение: Q=a; W — с; E=d. Без использования предиката cut таких
решений было бы три: (Q=a; W = с; E=d), (Q = c; W=d; Е=а),
(Q=d; W=a; E=c).
В языке используется понятие анонимной перемен-
ной, которая должна начинаться со знака подчеркива-
ния (______). Она вводится тогда, когда значение соответст-
вующего объекта является несущественным.
Рассмотрим пример:
detains
tip,fun:syibol
/» .объявление объектов tip, fun типа sytbol »/
л, koi:integer
ft объявление объектов x, koi целого типа »/
predicates
»s(tip,fon,i,koi)
ft здесь объекты tip, fun, i, koi имеют следуюжую содер-
хательиую интерпретацию: tip - тип микросхему fun -
реализуемая функции; л • число входов; koi - число
элементов в корпусе »/
is'oig(tip)
clauses
ts( klbblaJ, ije,2,4).
229
s(к1551а4,1_де,3,3).
s(k 155 la 1, ijie, 4,2).
s(kl551a2,ije,8,l).
s(kl55 Ini,ne,1,6).
s( kl55 lei,1li,2,4).
s(kl551il,1,2,4).
s(kl55113,i,3,3).
as(kl55116,i,4,2).
aabis(Y) is(Y,_,Z,_), Z>3.
/« «иоиение nsbig будет Banoinmci, если чисю
входов элемента бмьие трех »/
Так, отношение msbig будет истинно для тех элементов Y, для
которых число входов больше трех, вне зависимости от второго и чет-
вертого параметров отношения ms. Зададим цель: ms (k 1551аЗ, Y,_,_).
В результате получим: Y = i__пе (одно решение). Здесь нас интересо-
вало значение только второго параметра отношения ms. Точно так же
можно выбрать все элементы i, все элементы с двумя входами и т. п. Если
сформулировать цель: ms(X, Y, Z, F), Z<4, то получим все элементы
с числом входов меньше четырех (запятая перед Z воспринимается
как связка «и»).
7.2. ВВОД И ВЫВОД
Ввод и вывод в ПРОЛОГе организуется с помощью
специальных предикатов чтения и записи, которые могут
рассматриваться как аналоги соответствующих подпро-
грамм в языках ПАСКАЛЬ и СИ. Перечислим наиболее
часто используемые из этих предикатов:
readchar (Var) — считывает один символ с входного
потока (по умолчанию, с клавиатуры) и присваивает
его переменной Var;
readint(Var) — считывает целое число с входного пото-
ка и присваивает его переменной Var;
readin(Var) — считывает символы с входного потока
до нажатия клавиши ВВОД (символ возврата каретки).
Введенные символы присваиваются переменной Var, кото-
рая должна быть строковой (string) или символьной
(symbol);
readreal (Var) — считывает вещественноё’число с вход-
ного потока и присваивает его переменной Var;
write(Argl, Arg2,...) —выводит значения аргументов
в заданное активное окно на текущее устройство (по
умолчанию, на экран дисплея). Аргументы Argl, Arg2,..,
могут быть константами или переменными, которым
заранее присвоены требуемые значения. Пример использо-
вания предиката write был дан в § 7.1. Там же записан
стандартный предикат nl, который часто следует после
write и вызывает перевод каретки в начало следующей
строки.
230
В предикате write можно использовать символы, начи-
нающиеся со знака \. Они имеют специальные значения:
\к — символ, имеющий ASCII-код числа к;
\п — возврат каретки и перевод строки;
\t — табуляция.
По существу ввод и вывод в ПРОЛОГе и в других
языках мало различаются и реализуются довольно просто.
7.3. СПИСКИ И РЕКУРСИЯ
ПРОЛОГ позволяет использовать объекты, содержа-
щие другие объекты. Рассмотрим рис. 7.2, на котором
дана классификация некоторых задач, решаемых на этапе
логического проектирования цифровых устройств. Зада-
дим предикат logic (task). При этом задачей может быть
либо синтез, либо моделирование, либо диагностика. Од-
нако задача синтеза неодинаково решается по отношению
к комбинационным и последовательностным схемам.
Далее на рис. 7.2 имеют место другие разветвления.
Рис. 7.2. Классификация некоторых задач логического проектирования
231
Предположим, что в разделе clauses необходимо задать
факт: ”на этапе логического проектирования решается
задача синтеза комбинационной схемы сумматора”. Тогда
можно записать следующее предложение:
logic (synthesis (combi national______circuit (’’сумматор”))).
Здесь объект logic включает другой объект — synthesis,
который в свою очередь тоже включает другой объект —
combinational___________circuit. Ниже приведена программа, опи-
сывающая иерархию задач на рис. 7.2:
dona ins
task = synthesis(circnit); simulation; diagnostic
/» задача пкичает либо синтез кашчо скеи
(circuit), либо иодеаироваиие, либо диагностик; а/
circuit 1 sequential_circuit(synchr);
coibinational_circuit(syabol)
/к рассиатриваеиие сдеии могут бить комбинационными
и» последоватеиьиостииии; иосдедоватеиьиостиые
скеми каассифицирувтся по способу синхронизации к/
synch? = synchronous; asynchronous
/к способ мояет бить сиикроиный ни асиитроииий */
predicates
logic(task)
clauses
logic)simulation).
logic)diagnostic).
logic)synthesis!c<ahinational_circuit("деаифратор"))).
logic)synthesis)co»binational_circnit("суииатор"))).
logic) synthesis) coehinat ional_c ircuit ("иуДьтии дексор’))).
logic)synthesis)sequential_circuit(synchronous))),
logic(synthesis)sequential_circuit(asynchronous))).
/> приведенные факти могут иитерпретироватьси как задачи,
реиаемие на данной этапе; синтез асиикроиш посиедо-
ватедьиостиик сдеи; синтез chhipohhui последоватедь-
иостиид схем; синтез мультиплексоров и т.п. к/
При объявлении сложных объектов в разделе domains
используется точка с запятой (;), которая интерпрети-
руется как связка ИЛИ. Так, задачей может быть или
синтез, или моделирование, или диагностика (им. рис. 7.2).
Синтезируемые схемы являются последовательностными
либо комбинационными и т. п.
Сложные объекты и отношения могут быть заданы
рекурсивно, т. е. через самих себя. Рассмотрим пример
программы, осуществляющей рекурсивное вычисление
наибольшего общего делителя двух целых положительных
чисел:
/» нахождение иаибодьиего общего делители двух
цени положительных чисел >/
predicates
nod)integer,integer)
232
ft предикат nod позвоаает найти иаибоаьиий обций декитедь
двух цедык походите!ьиих чисед, используемых в ка-
честве его аргументов «/
goal wite("Введите первое число"), nl, readint(H),
игite("Введите второе число"), nl, readint(E),
nod(W,E).
/> ввод цеш чисел Я и К, дли которых находится
иаибольиий обдий делитель «/
clauses
nod(_,0).
/> если второй аргумент ди nod равен нулю, то
это отиоиеиие истииио »/
nod(X,Y) :- l-l nod Y, nod(Y,Z),
write("йанбодьиий обдий делитель - exit.
/< рекурсивное вычисление иаибольиего обдего делителя;
exit - Функция выхода в среду операционной системы
(сразу де после иакоядеиия реиеииа задачи) к/
В выражении Z = X mod Y переменная Z получает
значение остатка от деления X на Y. Все остальные
пояснения даны в комментариях к программе. В разделе
clauses задано правило рекурсивного определения отно-
шения nod. Если получить загрузочный модуль программы
и запустить его на выполнение, на экране появится сооб-
щение:
Введите первое число
Наберем 164 и нажмем клавишу ВВОД; появится новое
сообщение:
Введите второе число
Наберем 140 и нажмем клавишу ВВОД; на экране появит-
ся результат:
Наибольший общий делитель =4
В работе [15] приведена аналогичная программа
на языке СИ, а в гл. 5— на языке ПАСКАЛЬ. Кроме
того, в книге [10] дан подробный алгоритм решения
этой задачи.
Списки являются основной структурой данных в-ПРО-
ЛОГе. Они отдаленно соответствуют массивам в языках
ПАСКАЛЬ и СИ. Элементы списка разделяются запяты-
ми и заключаются в квадратные скобки. Рассмотрим
объявление:
domains
list = integer*
Оно задает список list целых чисел. Звездочка в объяв-
лении списка указывает на то, что в нем 0 (пустой список)
или более элементов. ПРОЛОГ обрабатывает список путем
233
разделения его на две части: начало, или заголовок
(head), и конец, или хвост (tail). Началом списка [1, 8,
36] является элемент 1, концом —новый список [8, 36].
Чтобы отделить начало от конца, используется знак ] Для
списка [ [1,6], [8,9],[]] началом является [1,6], концом —
[[8,9], []]; для списка [п] —п—это начало, а [] —
конец.
Ниже приводится пример программы, использующей списки
и позволяющей:
1) установить, принадлежит ли значение некоторой переменной
заданному списку;
2) построить список, содержащий общие элементы двух других
списков;
3) построить список элементов, которые есть в одном списке,
но в другом отсутствуют:
donains
intlist : integer*
/* объявлен список intlist элементов целого типа к/
I = integer
It объявлена иереиекиаа х целого типа к/
predicates
aenberfx,intlist)
/t aeiber устанавливает, прииацеш хи значение х
списку intlist »/
еоппо п(int11st,intli st,intlist)
/« connon позволяет выделить список (третий аргумент)
обдиг эаеиеитов других списков (первий и второй
аргументы) »/
тагп(intlist,intlist,intlist 1
/« гаги позволяет выделить список (третий аргумент)
элементов, шорне есть в одном списке (первий
аргумент), ио отсутствуют в другом (второй аргумент) «/
clauses
ne«ber( X, ).
/к устанавливаете!, есть хи значение х в заголовке списка к/
»e«ber(X,[_,’Tail]) ие«Ьег(Х,Та 11).
/к Устаиавливается, есть хи эиачеиие х в конце списка
(Tail) к/
conon(Ll,L2,[I]) яеиЬот(I,LI), neoberlI,L2).
It находятся обиие зхеиеити в списках LI и 12 >/
razn(LI,12,[X)) »eiber(X,LI), *:
not («eaber(X,L2)).
It находятся зхеиеити списка Li, которих нет в
списке L2 »/
Если запустить эту программу в среде ТУРБО ПРОЛОГа и в ответ
на сообщение Goal: ввести razn ([1,2], [2,3] ,Р), то будет получен ре-
зультат: Р= [1]. Здесь значение 1 есть в первом списке ([1,2]), но
отсутствует во втором ([2,3]). Предикат not дает истинное значение,
если его аргумент принимает ложное значение, и наоборот.
234
7А. АРИФМЕТИЧЕСКИЕ И ЛОГИЧЕСКИЕ ОПЕРАЦИИ
К этой группе операций в языке ПРОЛОГ относятся:
арифметические, логические, операции отношения. Ариф-
метические операции включают:
унарные + и —;
умножение (*) и деление (/);
сложение (+) и вычитание (—).
Приоритет этих операций уменьшается сверху вниз для
каждой группы. В выражениях они выполняются слева
направо. Порядок выполнения и приоритет могут регули-
роваться с помощью круглых скобок.
Операции отношения включают:
< — меньше;
<= — меньше или равно;
— равно;
> — больше;
>= — больше или равно;
О или >< — не равно.
Другие арифметические и логические операции вычис-
ляются с помощью специальных предикатов и функций,
которые приводятся ниже:
bitand(X, Y, Z) —поразрядное И над целыми двух-
байтными значениями X и Y. Результат передается в Z;
bitor(X, Y, Z) — подобна bitand, но выполняется опе-
рация поразрядное ИЛИ;
bitxor(X, Y, Z) —подобна bitand, но выполняется
операция поразрядное Исключающее ИЛИ;
bitnot (X, Z) — поразрядная инверсия целого двухбайт-
ного значения X. Результат передается в Z;
bitleft (X, N, Z) —поразрядный сдвиг целого двухбайт-
ного значения X на N позиций влево. Результат пере-
дается в Z;
bitright (X,N,Z) —подобна bitleft, но сдвиг осущест-
вляется вправо;
X mod Y — возвращает остаток от деления х на у;
X div Y — возвращает целую часть от деления х на у;
abs(X) — возвращает значение модуля х;
cos(X) —возвращает значение косинуса х;
sin(X) — возвращает значение синуса х;
tan(X) — возвращает значение тангенса х;
arctan (X) —возвращает значение арктангенса х;
ехр(Х) — возвращает значение ех;
1п(Х) — возвращает значение 1пх;
log(X) —возвращает значение Igx;
235
sqrt(X) — возвращает значение д/х7~
Шестнадцатеричные числа в языке ПРОЛОГ начи-
наются со знака $, например $ В8С6.
7.5. СТРУКТУРИРОВАННЫЕ ТИПЫ ДАННЫХ
Здесь будут рассмотрены работа с файлами и строками, а также
динамические базы данных. Все необходимые сведения, имеющие от-
ношение к организации файлов, были даны ранее.
В ПРОЛОГе файл может быть открыт: для чтения,
для записи, для добавления, для модификаций. Каждому
открытому файлу ставится в соответствие логическое имя.
Оно начинается со строчной буквы, должно быть объяв-
лено в разделе domains и иметь тип file. Четыре логических
имени — printer, screen, keyboard и coml — зарезерви-
рованы и относятся соответственно к принтеру, экрану
дисплея, клавиатуре и первому коммуникационному ка-
налу.
Опишем часто используемые стандартные предикаты
для работы с файлами:
openread (логическое имя файла, физическое имя фай-
ла) — файл с заданным физическим именем открывается
для чтения, и ему ставится в соответствие логическое
имя; например: openread (myfile, ’’prim.pro”);
openwrite (логическое имя файла, физическое имя
файла) — подобен openread, но файл открывается для
записи;
openappend (логическое имя файла, физическое имя
файла) — подобен openread, но файл открывается для
дополнения;
openmodify (логическое имя файла, физическое имя
файла) — подобен openread, но файл открывается для
модификаций (чтения и записи);
closefile (логическое имя файла) — файл с указанным
логическим именем закрывается; и
readdevice (логическое имя файла) — перераспреде-
ляет стандартный входной поток на файл с заданным
логическим именем, который открывается для чтения;
writedevice (логическое имя файла) —перераспре-
деляет стандартный выходной поток на файл с заданным
логическим именем, который открывается для записи или
добавления;
file_str (физическое имя файла, str) — считывает
данные из файла с указанным физическим именем и по-
мещает их в str (переменная str должна быть символь-
236
ной или строковой). Символом конца файла является
Ctrl —Z (ASCII-код 26);
filepos (логическое имя файла, позиция, режим) —
устанавливает текущий указатель на заданную позицию
в указанном файле. Объект, указывающий позицию, дол-
жен быть вещественного типа (real), а режим — целого
типа (integer). Если на месте режима записан 0 (нуль),
позиция отсчитывается от начала файла; если 1,— от те-
кущего значения указателя; если 2,— от конца файла.
Этот предикат используется для прямого доступа к файлу.
Рассмотрим пример двух программ. Первая из них осуществляет
запись символов в файл myfile.f, который создается на текущем диске.
Запись прекращается после ввода символа =Н=:
doaains
file - ayfile
/f ойввиетси логическое нив файла ayfile «/
predicates
read_in_loop
goal
«rilefSta программа читает символ с клаваатури\п",
"(без иалатин швинн ВВОД) и записивает ",
'его в файл ayfile.f\n Ди заиериеш работа ",
пахните кяавииу #\п"),
opensrite(ayfile, "ayfile.f"),
/f файл ayfile откриваетси ди записи >/
Hritedevicefayfile),
/f стаидартиай в миной поток связивается с файлом ayfile а/
not(read_in_loop),
/г иредикат, обеспечиваний циклическое чтение символов
до поивиеиии знака I к/
closefile(ayfile),
/к закритие Файла ayfile >/
writedevicefscreen),
/к стаидартиий виходиой поток свизиваетси с экраном дисплеи к/
нгЦе("\пзаинсь в файл ayfile.f произведеиа\п“).
clauses
read_in_loop:-readchar(X), Хо Mrite(X), read_in_loop.
/к вместо notfread_in_loop) в goal иолио было записать
read.in.loop (без not), а здесь дописать read.in_.loop
(как неходкий, так и изиеиеииий вариаити иеобходими для
того, чтоби виралеиие цели ие стало яояиым до закритиа
файла ayfile) к/
Вторая программа позволяет прочитать любой символ из указан-
ного файла и вывести его на экран дисплея:
doiains
file inflle
predicates
position
. goal
MtitefC каш файлом Вы хотите работать?\п"),
readln(FNaae),
237
/» с каавиатуры вводится физическое иия Файн */
openreadfinfile, FHaie),
/* Файд infile открывается jii чтеш */
posItioa.
/* внзимет чтение снвош из файла infile«/
clauses
position
readdevice(keyboard),
/• стацартнй вяодиой поток стзиваетп с главиатурой »/
nl, Hritef"Введите иоиер ыоэнции:
readreal(X),
/* вводится иоиер ыоэицяи »/
readdevicefinfile),
/> стандарт ии.'. входной иотог свиэивается с файд ок infile */
filepost iniile,X,0),
/« текучий указатель устанавливаете! аа иоэицию I, которая
отсчитивается от начала файла */
readchar(Y),
/» из позиции X читается символ и назначается переменной Y »/
nitef здесь зависай символ:
position.
/» чтение следящего сиивола «/
После запуска первой программы на выполнение в среде MS-DOS
можно набирать любые символы (они записываются в файл myfile.f,
но не отображаются на экране дисплея в связи с переназначением
выходного потока). После ввода знака # программа завершает работу.
Во второй программе сначала запрашивается имя файла, с кото-
рым необходимо работать. Введем, например, myfile.f. После этого
можно будет прочитать символ, записанный в любой позиции этого
файла (тем самым можно убедиться и в правильности работы первой
программы, поскольку myfile.f сформирован в ней).
Стандартные предикаты обработки строк в ПРОЛОГе
во многом подобны аналогичным подпрограммам для
языков СИ и ПАСКАЛЬ. Рассмотрим некоторые из них:
concat(Strl, Str2, Strl 2) —утверждает, что Strl
2 — это объединение CTpOK~Strl и Str2, при этом по край^
ней мере два параметра должны быть определены за-
ранее;
frontchar(Strl______2, Strl, Str2) — работает в соответст-
вии с уравнением: Strl___2= (объединение Stf’l и Str2).
Строка Strl___2 должна быть задана либо задаются обе
строки Strl и Str2;
frontstr(N, Strl_2, Strl, Str2) — назначает первые N
символов Strl___2 строке Strl, а остальные — Str2. При
вызове N и Strl_____2 должны быть определены, a Strl
и Str2 — нет;
isname(str) —проверяет строку Str на синтаксис
ПРОЛОГа;
str__char (Str, С) —перевод строки Str в символ С;
str__int(Str, I) — перевод строки Str в целое I;
238
str_len(Str, L) —возвращает длину строки Str или
проверяет, имеет ли она длину L;
str_real (Str, R) — перевод строки Str в веществен-
ное число R;
upper__lower (Upstr, Lostr) — переводит прописные
буквы (Upstr) в строчные (Lostr).
Опишем теперь способ объявления динамической
базы данных, в которую факты могут добавляться во
время выполнения программы или выбираться из файла
на диске путем использования стандартного предиката
consult. Этим целям служит ключевое слово database.
Например:
domains
tip,fun=syibol
It обившие объепов tip, fun типа syibol */
i,kol=integei
/» обившие обгепов i, koi целого run »/
database
is(tip,fuD,x,kol)
/» здесв obtetTK tip, fun, i, koi ииеюг сзедуиую содер-
хатепиу» иитериретацию-. tip - тиы ииросаеии; fun -
ревизуема рувщив; а - чамо вводов; koi - вино
заеиеитов в юрнусе */
clauses
s(kl551a3,ije,2,4).
BS(kl551a4, ije, 3,3).
BS(kl551al,ijie,4,2).
BS(kl551a2,ijie,e,1).
BS(kl551nl,ne,l,6).
BS(kl551el,ili,i,4).
BS(kl551il,i,2,4).
BS(kl55H3,i,3,3).
BS(kl551i6,i,4,2).
Здесь предварительно создана база данных на основании
фактов, описанных в разделе clauses. Ее можно изменять
с помощью следующих трех стандартных предикатов:
asserta — обеспечивает запись в базу данных нового
факта перед имеющимися фактами для заданного отно-
шения;
assertz — обеспечивает запись в базу данных нового
факта после всех имеющихся фактов для заданного
отношения;
retract — обеспечивает удаление факта из базы данных
для заданного отношения.
Запустим приведенную программу на выполнение
в среде ТУРБО ПРОЛОГа. Если в ответ на сообщение
Goal: ввести строку assertz (ms(kl55irl, rg,4,4)), то факт
ms(kl55irl, rg,4,4) будет добавлен в базу данных. Если же
239
ввести строку (retract (ms (Q,i_ne,W,E)), то из базы
данных будут удалены все объекты для элементов типа
i__пе. При необходимости сохранения базы данных на
диске в заданном файле (например, mybase.dba) в ответ
на сообщение Goal: необходимо ввести строку: save
(’’mybase.dba”) Затем в этой же или в другой программе
на основе полученного файла можно создать новую базу
данных. Для этого в ответ на сообщение Goal: необходимо
ввести строку: consult (’’mybase.dba”). В результате су-
ществующая база данных дополняется объектами из фай-
ла mybase.dba.
7.6. МОДУЛЬНОЕ ПРОГРАММИРОВАНИЕ
Модульное программирование позволяет разделить
сложную программу на совокупность более простых
взаимодействующих модулей, которые могут быть напи-
саны, отредактированы и скомпилированы раздельно.
Для этих целей в ПРОЛОГе используются средства
создания проектов (project) и глобальные объявления
(global). Если программа будет создаваться из несколь-
ких модулей, необходимо подготовить файл, содержащий
список их имен. Этот файл имеет следующий формат:
имя файла с первым модулем
имя файла со вторым модулем
Например, для программ main.pro и fun.pro будет
записано:
main
fun
Этот файл (и другие подобные файлы) должен иметь
тип prj (например, myprog.prj). Он создается с помощью
опции Edit PRJ file в подменю Options. KpoMte того, имя
project должно быть задано в каждом модуле с помощью
соответствующей директивы компилятора, например:
project ’’MYPROG”).
По умолчанию, все объекты, используемые в модуле,
являются локальными. Взаимодействие нескольких моду-
лей осуществляется через общие (глобальные) области,
которые объявляются с помощью ключевого слова glo-
bal. Они должны быть известны всем взаимодействующим
модулям. Наиболее просто это достигается путем создания
файла глобальных описаний и включения его во все мо-
240
дули с помощью директивы компилятора include. Объяв-
ление глобальных предикатов имеет отличия и выпол-
няется по следующей схеме:
имя(х!....хп) — (fl__l,...,fl_п) (f2_1...f2__n).,.
Здесь xl,...,xn — заданные объекты; в скобках для каждого
объекта указаны назначения: i— значение объекта из-
вестно на входе (входной параметр); о — значение объек-
та известно на выходе (выходной параметр). Последо-
вательности в круглых скобках задают все возможные
назначения (шаблоны). Если глобальные описания по-
местить в файл GLOBALS.PRO, а project-файл имеет
имя MYPROG.PRJ, каждый модуль должен начинаться
со следующих двух директив:
project ’’MYPROG”
include ’’GLOBALS.PRO”
Раздел goal может быть только водном (главном) модуле.
Рассмотрим пример подготовки программы, содержащей два
модуля — main.pro и fun.pro. Текст main.pro записывается в таком виде:
project ”H¥P80G’
include "GLOBALS.PBO*
predicates
privet
goal
privet.
clauses
privet:-systeuf -cis'), /» очисти aitpasa »/
iake»indo«( 1,7,7,'И<щшое арограииироваше',
10,10,7,50),
MritefBat Вас зовуt?\n\n'),
readln(Baae),
aodul(Baae).
Текст fun.pro представляется в следующем виде:
project ‘MYPROG"
include "GLOBALS.PRO"
clauses
modul(Naee):-write("Здравствуй, ".Bane), nl,
HritefBaime »6y> Kiasssp"),
readchar(_).
Предикат makewindow открывает окно и будет описан в следующем
параграфе. Предикат system обеспечивает доступ к средствам опера-
ционной системы.
Рассмотрим раздел GLOBALS.PRO:
global detains
паше г string
global predicates
aodulfnaie] - (i)
241
Здесь можно было ограничиться только разделом глобальных пре-
дикатов:
global predicates
iodul(string) - |i)
Далее необходимо выполнить следующие действия:
1) создать файл MYPROG.PRJ следующего вида:
main fun
2) создать файл GLOBALS.PRO глобальных объявлений;
3) создать файлы модулей main.pro и fun.pro. Сгенерировать фай-
лы main.obj и fun.obj;
4) создать выполняемую программу MYPROG.EXE, для чего
выполнить опцию Project подменю Compile.
После запуска MYPROG.EXE на выполнение на экране появится
окно, и в его верхней части текст—Модульное программирование.
В окне сформулирован вопрос: «Как Вас зовут?». Если указать имя,
например Вася, программа ответит: «Здравствуй, Вася», и на следую-
щей строке появится: «Нажмите любую клавишу». После выполнения
предписанных действий программа завершает свою работу.
7.7. СТАНДАРТНЫЕ ПРЕДИКАТЫ
Ниже перечисляются стандартные (библиотечные)
предикаты ТУРБО ПРОЛОГа. При этом приняты сле-
дующие правила. Сначала записываются имя предиката
и способ его вызова, далее — типы параметров в соот-
ветствующих позициях предиката, затем — описание шаб-
лонов для всех параметров (i — input или вход, о — output
или выход; каждый шаблон заключается в круглые скоб-
ки). Если некоторый предикат был описан в предыду-
щих параграфах, для него не приводятся никакие пояс-
нения:
asserta ((факт)) (факт) (i);
assertz ((факт)) (факт) (i);
attribute (At) (integer) (i) (о) —устанавливает за-
данный атрибут для экрана либо передает в At текущее
значение атрибута;
beep — подача звукового сигнала;
bios(IntN, Rgln, RgOut) (integer, regdom, regdom)
(i, i, o) — обращение к прерыванию IntN; здесь regdom =
= reg(AX, BX, CX, DX, SI, DI, DS, ES), где все пере-
менные являются целыми (они соответствуют внутренним
регистрам микропроцессора с теми же именами);
bound(Var) ((переменная)) (о) —дает истинный ре-
зультат, если Var присвоено какое-либо значение;
char__int(CP, IP) (char, integer) (i, o) (o, i) (i, i) —
в случае (i, о) находит ASCII-код СР и передает его IP;
в случае (o,i) находит символ, соответствующий ASCII-
242
кбду IP, и передает его СР; в случае (i,i) дает истинный
результат, если СР имеет ASCII-код IP;
clearwindow — очищает текущее активное окно, запол-
няя его фоновым цветом;
closefile(FName) (file) (i);
consult (DOSFName) (string) (i);
cursor (Row, Column) (integer, integer) (i,i) (o,o) —
в случае (i,i) перемещает курсор в заданную позицию
текущего активного окна; в случае (о,о) передает в Row
и Column текущие координаты курсора;
cursorform (Start, End) (integer, integer) (i,i) —уста-
навливает размер курсора от Start до End, которые могут
принимать значения в интервале от 1 до 14;
date (Year, Month, Day) (integer, integer, integer) (i,i,
i) (0,0,0) — считывает (о,о,о) или устанавливает (i,i,i)
текущую дату;
deletfile (DOSFName) (string) (i) —удаляет файл
DOSFName из текущего активного каталога;
dir(PathN, FileSpec, DOSFName) (string, string,
string) (i,i,o) — высвечивает имена файлов в активном
окне по их спецификациям FileSpec и маршрутам PathN.
Пользователь может выбрать имя, возвращаемое в
DOSFName (с помощью клавиш управления курсором
и клавиши ВВОД);
disk(DOSPath) (string) (i) (о) —устанавливает (i)
или считывает (о) текущий каталог (DOSPath);
display (Str) (string) (i) —отображает содержимое
Str в текущем активном окне;
dot (Row, Column, Color) (integer, integer, integer)
(i,i,i) (i,i,o) — при (i,i,i) записывается точка цвета Color
в заданную позицию (Row, Column); при (i,i,o) считы-
вается номер цвета для заданной точки;
edit (InStr, OutStr) (string, string) (i,o) —вызывает
редактор ТУРБО ПРОЛОГа, при этом InStr может
изменяться в активном окне, в результате чего форми-
руется OutStr;
eof(SymFName) (file) (i) —проверяет, находится ли
указатель позиции текущего файла в его конце (если да,
то eof завершается успешно; в противном случае — нет);
existfile(DOSFName) (string) (i) —завершается ус-
пешно, если DOSFName есть в текущем директории;
exit — прекращает выполнение программы;
fail—является причиной невыполнения предиката и,
следовательно, возврата в предыдущее состояние;
field_attr(Row, Column, L, At) (integer, integer,
243
integer, integer) (i,i,i,i) (i,i,i,o)—в случае (i,i,i,o) атрибут
поля длиной L текущего активного окна, начинающегося
с Row и Column, передается переменной At; в случае
(i,i,i,i) все позиции указанного выше поля принимают
атрибут At;
field_str (Row, Column, L, Str) (integer, integer,
integer, string) (i,i,i,i) (i,i,i,o) — подобен предикату
field_attr, но на экран записывается (в случае i,i,i,i)
либо считывается (в случае i,i,i,o) строка Str;
filepos(SFName, FP, Mode) (file, real, integer) (i,i,i)
(i,o,i);
file__str(DOSFName, Str) (string, string) (i,o);
free(Var) (переменная) (о) —выполняется, если пе-
ременной Var не присвоено значение;
frontchar (Str, F, R) (string, char, string) (i,o,o) (i,i,o)
(i,o,i) (i,i,i) (o,i,i);
fronttoken (Str, F, R) (string, string, string) (i,o,o)
(i,i,o) (i,o,i) (i,i,i) (o,i,i) — подобен предикату frontchar,
однако второй параметр имеет тип string (см. также
§7.5);
graphics (Mode, Palette, Background) (integer, integer,
integer) (i,i,i) —устанавливает графический режим Mode,
позволяет задать палитру (Palette) и цвет фона (Back-
ground) ;
isname(SP) (string) (i);
line(RowS, ColS, RowE, ColE, Color) (integer, inte-
ger, integer, integer, integer) (i,i,i,i,i) — проводит линию
из позиции (RowS, ColS) в позицию (RowE, ColE), имею-
щую цвет Color (работает в графическом режиме);
makewindow (No, At, FAt, Str, Row, Col, H, W) (integer,
integer, integer, string, integer, integer, integer, integer)
(i,i,i,i,i,i,i,i) — определяет окно с заданным номером (No).
Если FAT =4 О, окно берется в рамку и верхняя граница
включает текст (Str). Параметры Row, Col, Н, W задают
размер окна (позицию левого верхнего угла, ё'ысоту и ши-
рину). Значение At назначает атрибут выводимых сим-
волов;
membyte(Seg, Off, Byte) (integer, integer, integer)
(i,i,i) (i,i,o) — байт (Byte) помещается в память (i,i,i)
либо считывается из памяти (i,i,o). Местоположение
в памяти определяется сегментным адресом (Seg) и сме-
щением (Off);
memword(Seg, Off, Word) (integer, integer, integer)
(i,i,i) (i,i,o) — аналогичен membyte, но считывается и за-
писывается слово Word;
244
openappend (SFName, DODFName) (file, string) (i, i);
openmodify(SFName, DOSFName) (file, string) (i, i);
openread (SFName, DOSFName) (file, string) (i, i);
openwrite(SFName, DOSFName) (file, string) (i, i);
pencolor (Color) (integer) (i) — устанавливает цвет;
portbyte(PNo, Vai) (integer, integer) (i, i) (i, o) — по-
лучает (i, о) или передает (i, i) значение Vai размером
один байт в порт ввода-вывода с номером PNo;
prt_dword(Str, Seg, Off) (string, integer, integer)
(i, o, o) (o, i, i) — если Str имеет какое-либо значение, то
Seg (сегментный адрес) и Off (смещение) получат значение,
связанное с местоположением Str(i, о, о); если Seg и Off
имеют какие-либо значения, то Str — первый символ в
строке (по адресу Seg, Off), завершаемой нулевым бай-
том (о, i, i);
readchar(CV) (char) (о);
readdevice(SFName) (symbol) (i) (o);
readint(IV) (integer) (o);
readln(Str) (string) (o);
readreal(RV) (real) (o);
removewindow — удаляет текущее активное окно;
renamefile(OldDOSFName, NewDOSFName) (string,
string) (i, i) — переименовывает файл (меняет OldDOS-
FName на NewDOSFName);
retract ( (факт)) (факт) (i);
save(DOSFName) (string) (i);
shiftwindow(No) (integer) (i) (о) — в случае (i)
устанавливает текущее активное окно с номером No; в слу-
чае (о) переменная No получает номер текущего активного
окна;
sound (Duration, Frequency) (integer, integer) (i, i) —
вызывает звуковой сигнал длительностью Duration (в со-
тых долях секунды) и частотой Frequency;
str_attr (Row, Col, At) (integer, integer, integer) (i,i, i)
(i, i, o) —устанавливает (i, i, i) либо считывает (i, i, о)
значения атрибута At для символа в позиции экрана
(Row, Col);
str_char (Row, Col, C) (integer, integer, char) (i, i, i)
(i, i, o) — аналогичен scr_attr, но выводит и считывает
символ С;
str char(Str, С) (string, char) (i, о) (о, i) (i, i);
str int(Str, I) (string, integer) (i, o) (o, i) (i, i);
str len(Str, L) (string, integer) (i, i) (i, o);
str real(Str, R) (string, real) (i, o) (o, i) (i, i);
system(DOSComStr) (string) (i) —вызывает выпол-
245
нение в MS-DOS команды, заданной строкой DOSComStr;
text — перевод экрана в текстовой режим;
time (Hours, Minutes, Seconds, HungSec) (integer, inte-
ger, integer, integer) (i, i, i, i) (o, o, o, o) — аналогичен пре-
дикату date, но устанавливает (i, i, i, i) или считывает
(о, о, о, о) текущее время;
trace (Status) (symbol) (i) (о) — в случае (i) включает
trace(on) или выключает trace (off) трассировку; в случае
(о) передает переменной Status значение оп или off;
upper__lower (UpStr, LoStr) (string, string) (i, i) (i, o)
(o, i);
window___attr(At) (integer) (i) —задает символам в
текущем активном окне атрибут At;
window___str (Str) (string) (i) (o) —строка Str выво-
дится (i) либо считывается (о) из текущего активного
окна. Объект Str будет включать все данные в окне;
write(Argl, ..., Argn)((i)*);
writedevice(SFName) (symbol) (i) (o);
writef(Format, Argl, ..., Argn) (i, (i)*) —подобен
write, но осуществляет форматированный вывод в соот-
ветствии с параметром Format, который представляется
в виде: % — т. р. Здесь знак «—» указывает на выравни-
вание по левой границе (по умолчанию, по правой грани-
це); m — минимальная ширина поля (необязательный
параметр); р — точность чисел с плавающей точкой или
максимальное число символов, которые будут выведены
в одной строке. Поле р содержит одну из букв f, е или g,
обозначающих: f — вещественные числа в десятичном
представлении (задается по умолчанию); е — веществен-
ные числа в экспоненциальном представлении; g — ис-
пользование самого короткого формата.
8. ЯЗЫК АССЕМБЛЕРА
8.1. ОБЩИЕ СВЕДЕНИЯ
Ассемблер — это средство, помогающее готовить про-
граммы в машинных кодах. Имеется несколько транслято-
ров с этого языка, разработанных различными фирмами,
например ASM-86 фирмы Intel, MASM фирмы Microsoft
и TASM фирмы Borland. В данном пособии описывается
ассемблер MASM версии 5.1.
Нашей целью является рассмотрение вопросов разра-
ботки процедур на ассемблере, объединяемых с програм-
мами на языках высокого уровня, и небольших резидент-
ных программ, расширяющих функции BIOS ПЭВМ.
Система команд микропроцессора Intel 8086, являю-
щегося базовым для ПЭВМ семейства IBM PC, содержит
135 инструкций, каждая из которых разделяется на группы
битов, или поля. Поле кода операции определяет тип ма-
шинной команды, а остальные поля, называемые операн-
дами, идентифицируют требуемую команде информацию.
Операнд может содержать данное, часть адреса данного,
косвенный указатель на данное и т. п. Способ определения
местонахождения операнда называется режимом адреса-
ции. Для микропроцессора Intel 8086 режимы адресации
делятся на два класса: для данных и для переходов.
Первые включают следующие способы:
1) непосредственный, при котором операнд длиной• 8
или 16 бит является частью команды (рис. 8.1,а);
2) прямой, при котором 16-битовый исполнительный
адрес (ИА) операнда является частью команды
(рис. 8.1, б);
3) регистровый, при котором операнд может нахо-
диться в одном из регистров: АХ, АН, AL, ВХ, ВН, BL,
СХ, CH, CL, DX, DH, DL, BP, SP, SI, DI (рис. 8.1,в);
4) регистровый косвенный, при котором ИА операнда
находится в одном из указанных регистров: ГВХ], [SI1,
[DI] (рис. 8.1,г);
247
КОМАНДА
а
| ДАННОЕ |
КОМАНДА ПАМЯТЬ
| ИА | ДАННОЕ |
Ь КОМАНДА РЕГИСТР
| РЕГИСТР ----------------— ^ДАННОЕ "|
В
КОМАНДА РЕГИСТР ПАМЯТЬ
| РЕГИСТР 7^]-----ИА »^|------------^РдАННОЕ ~|
а
КОМАНДА
(регистр! СМЕЩЕНИЕ Я----------1
«-------«-----—-----1 f ПАМЯТЬ
РЕГИСТР ---->[ЛЯННОЕ_|
| АДРЕС -------------*
КОМАНДА
индексный регистр БАЗОВЫЙ РЕГИСТР
РЕГИСТР
| БАЗА •
РЕГИСТР
| ИНДЕКС «-]-
Ж
команда
ИНДЕКСНЫЙ РЕГИСТР БАЗОВЫЙ РЕГИСТР СМЕЩЕНИЕ •-
РЕГИСТР , ПАМЯТЬ
| БЯЗЯ «-]---*“(£)------*~| ЛЯННОЕ ~|
РЕГИСТР
(ИНДЕКС —|-------
Рис. 8.1. Режимы адресации данных
5) регистровый относительный, при котором ИА вы-
числяется как сумма 8- или 16-битового смещения и со-
держимого базового ([ВХ],[ВР]) или индексного
([SI] , [DI]) регистра (рис. 8.1,с?);
6) базовый индексный, при котором ИА определяется
как сумма содержимого базового ([ВХ], [ВР]) и индекс-
ного ([SI, [DI] (регистров (рис. 8.1,е);
7) относительный базовый индексный, при котором
ИА равен сумме адреса, который вычисляется в базово-
индексном режиме, и 8- или 16-битового смещения
(рис. 8.1,ж).
248
Примеры ассемблерных мнемоник для различных ре-
жимов адресации данных приведены ниже; команда
MOV АХ, OPR пересылает OPR в регистр АХ:
MOV AX,55 ; Непосредственный
MOV AX, VAR ; Прямой
MOV AX,BX ; Регистровый
MOV AX, [BX] ; Регистровый косвенный
MOV AX, [BX+ 10] ; Регистровый относительный
MOV AX, [BP+DI] ; Базовый индексный
MOV AX, [BP + SI+4] ; Относительный базовый индексный
При выполнении программ микропроцессор реализует
такую последовательность действий: 1) выбирает команду
по адресу, содержащемуся в регистре IP; 2) загружает
команду в программно-недоступный регистр и дешифри-
рует ее с одновременным инкрементом IP для адресации
следующей команды; 3) выполняет команду, а в случае
команды перехода загружает в IP адрес перехода; 4) про-
веряет запрос прерывания и переходит к шагу 1 или на
программу обработки прерывания. При необходимости
изменения последовательности выполнения команд про-
граммист использует команды передачи управления. Для
таких команд (условные и безусловные переходы, вызовы
процедур) существует четыре режима адресации пере-
ходов:
1) внутрисегментный прямой переход, при котором
адрес команды в сегменте кода определяется как сумма
содержимого регистра IP (счетчика команд) и 8- или
16-битового смещения. В командах условных переходов
допускается использовать только 8-битовое смещение
(рис. 8.2,а);
2) внутрисегментный косвенный переход использует-
ся только в командах безусловного перехода, при этом
содержимое регистра IP заменяется 16-битовым значением
выбранного регистра или ячейки, которые указываются в
любом из режимов адресации данных, кроме непосред-
ственного (рис. 8.2,6);
3) межсегментный прямой переход, при котором со-
держимое регистров IP и CS заменяется двумя словами,
располагающимися непосредственно в самой команде
(рис. 8.2,в);
4) межсегментный косвенный переход, при котором
содержимое регистров IP и CS заменяется двумя после-
довательно расположенными в памяти словами. Эти
249
КОМАНДА
| смещение"*]-------1
(7)-----► ИА ПЕРЕХОДА
I 1Р -I-------------1
КОМАНДА
Рис. 8.2. Режимы адресации переходов
ь
слова могут быть указаны в любом режиме адреса-
ции операндов, кроме непосредственного и регистрового
(рис. 8.2, г).
Примеры ассемблерных мнемоник для различных ре-
жимов адресации переходов приведены ниже:
JMP LAB ; Внутрисегментный^ррямой
JMP [ВХ] ; Внутрисегментный’ косвенный
JMP FAR PTR LAB ; Межсегментный прямой
JMP DWORD PTR [ВХ] ; Межсегментный косвенный
Как было указано выше, микропроцессор Intel 8086 ге-
нерирует 20-разрядный физический адрес, состоящий из
16-разрядного адреса сегмента и 16-разрядного смещения.
При этом используются следующие правила адресации:
1) выборка команд происходит только по адресу, задан-
ному регистрами IP и CS; 2) регистр SP применяется
только как смещение по отношению к регистру SS; 3) ко-
250
манды работы со строками, использующие регистр ES, не
могут выбирать вместо него другие регистры сегментов;
4) если регистр ВХ является базовым, то, по умолчанию,
операнд находится в сегменте данных и для вычисления
его физического адреса используется регистр DS; 5) если
базовым является регистр ВР, то операнд находится в сте-
ке и для вычисления адреса используется регистр SS;
6) если используются оба регистра — базовый и индекс-
ный, то операнд находится в сегменте, на который ука-
зывает базовый регистр; 7) если используется только
индексный регистр, то операнд находится в сегменте
данных DS.
Так как каждая команда, работающая с памятью, ис-
пользует регистр сегмента, ассемблер должен определить,
какой именно регистр должен выбираться в каждом кон-
кретном случае. Это задается адресным выражением, за-
писанным в исходном операторе. Использование регистров
сегментов, принятое в правилах 4—7, можно изменить с
помощью префикса замены сегмента, включаемого в каж-
дую команду либо программистом, либо с помощью ди-
рективы ASSUME, устанавливающей соответствие между
регистром сегмента и именем сегмента. Если необходимо
изменить сегмент, это следует указать при каждом обра-
щении к данным. Достаточно задать соответствие в
ASSUME, и все обращения к памяти будут автоматиче-
ски генерироваться в нужный код. Использование тех или
иных сегментов приведено в табл. 8.L
Таблица 8.1
Регистры, используемые для определения исполнительного адреса По умолчанию С префиксом замены
IP (счетчик команд) CS Нет
SP (указатель вершины стека) SS Нет
ВР (указатель слова в сегменте стека) SS CS, DS, ES
ВХ (регистр базы) DS CS,- SS,- ES
SI или DI (исключая адресацию строк) DS CS, SS, ES
SI (указатель строки-источника) DS CS, SS, ES
DI (указатель строки-приемника) ES Нет
BP + SI или BP + DI SS CS, DS, ES
Стек представляет собой область памяти для времен-
ного хранения данных. Регистр SS определяет базовый
адрес, а регистр SP — наибольшее допустимое смещение
в сегменте стека. Здесь используется косвенная адреса-
ция с помощью указателя SP; при включении элемента в
стек (это всегда слово) происходит автоматическое умень-
251
шение SP на 2, а при извлечении — увеличение на 2.
Адрес последнего включенного элемента называется вер-
шиной. Стек доступен программисту с помощью команд
PUSH и POP. Он применяется при возникновении преры-
ваний для сохранения состояния процессора, однако наи-
более важное его использование связано с передачей па-
раметров в процедуры.
Микропроцессор Intel 8086 имеет возможность реаги-
ровать на внешние события посредством вызова одной
из набора программ обслуживания. Событие, вызывающее
переход на такую программу, называется прерыванием.
Возможна обработка двух классов прерываний; внешних
и внутренних. Внешние прерывания инициируются аппа-
ратным сигналом на выводах микропроцессора INT или
NMI, поступающим от периферийных устройств, а внутрен-
ние прерывания возникают при выполнении программ
(фиксируют состояние процессора или генерируются ко-
мандой).
Независимо от типа прерывания возникающие при этом
действия одинаковы. Для того чтобы микропроцессор
смог начать выполнение программы обработки, он должен
завершить текущую команду, если ею не являются коман-
ды HLT или WAIT. Префикс — часть команды, и поэтому
запрос прерывания не распознается между префиксом
и командой. Если в качестве операнда команд MOV и POP
указан сегментный регистр, то запрос прерывания не рас-
познается до завершения следующей за ними команды,
что позволяет модифицировать указатели без прерываний;
это особенно важно для пары SS:SP. После распознава-
ния прерывания микропроцессор реализует следующие
действия: 1) определяет тип прерывания N; 2) текущее
содержимое регистра признаков (PSW), CS и IP вклю-
чается в стек; 3) биты условий TF и IF сбрасываются;
4) содержимое ячейки памяти 4* N передается в IP, а со-
держимое 4*N4-2 — в CS, т. е. управление передается по
вектору N: ;5) начинается выполнение процедуры преры-
вания; 6) команда IRET извлекает из стека IP, CS и PSW.
Команды МП можно разделить на 6 функциональных
групп: 1) пересылки данных; 2) арифметические; 3) логи-
ческие; 4) для работы со строками; 5) передачи управле-
ния; 6) управления микропроцессором.
Каждая из первых трех групп в свою очередь подраз-
деляется на ряд подгрупп в зависимости от того, работает
ли команда над непосредственными данными, регистрами
или областями памяти, обрабатываются ли байты или сло-
252
ва, какой принят способ адресации. Текст программы дает
ассемблеру достаточно информации для генерации необ-
ходимого машинного кода. Используемые при рассмотре-
нии алгоритмов выполнения команд сокращения и услов-
ные обозначения сведены в табл. 8.2.
Таблица 8.2
Наименование/Обозначение Смысловое значение
OPR SRC DST REG RSRC RDST CNT D1SP D8 DI6 ADDR ЕА SEG DATA Операнд Операнд-источник Операнд-получатель Регистр Регистр-источник Регистр-пол уча тель Счетчик Смещение (общее обозначение) 8-битовое смещение 16-битовое смещение Адрес Эффективный адрес Сегмент Непосредственный операнд (общее обо- значение)
DATA8 DATA 16 АХ, ВХ, СХ, DX, AL, АН, BL, ВН, CL, CH, DL, DH, ВР, SP, SI, DI, 1Р CS, SS, ES, DS 8-битовый непосредственный операнд 16-битовый непосредственный операнд Регистры микропроцессора Intel 8086 Сегментные регистры микропроцессора Intel 8086
DF, IF, ТЕ Управляющие флажки микропроцессора Intel 8086
OF, SF, ZF, AF, PF, CF Флажки условий микропроцессора Intel 8086
ч— Заменяется на Обменивается с
(X) AND OR XOR NOT(X) Содержимое X Логическое И Логическое ИЛИ Логическое Исключающее ИЛИ Инверсия X
8.2. СИСТЕМА КОМАНД МИКРОПРОЦЕССОРА INTEL 8086
8.2.1. Команды пересылки данных
Существуют четыре класса команд пересылки данных:
1) общего назначения; 2) работающие с аккумулятором;
3 команды пересылки адресов; 4) пересылки битов усло-
253
вий. На биты условий из команд этой группы воздействуют
только SAHF и POPF.
Команды пересылки данных общего назначения
(табл. 8.3) — единственные, которые позволяют в качестве
Таблица 8.3
Действие Мнемоника и формат Описание
Передать
Включить в стек
Извлечь из стека
Обменять
MOV DST, SRC
PUSH SRC
POP DST
XCHG OPR1, OPR2
(DST)-<-(SRC)
(SP)^(SP) — 2;
((SP) 4-l:(SP))-<-
-—(SRC)
(DST) — ((SP) + I
+ 1: (SP));
(SP)^(SP) +2
(OPR I)- - (OPR2)
операнда использовать регистр сегмента. Команда MOV
выполняет пересылку байта или слова из источника
(правый операнд) в приемник (левый операнд). Команда
PUSH уменьшает регистр SP на 2 и пересылает операнд
в стек по адресу, указанному регистром SP. Команда POP
пересылает слово из стека по адресу, указанному регист-
ром SP, в поле операнда и увеличивает регистр SP на 2.
Команда XCHG меняет байты или слова, адресуемые
операндами. Регистры сегментов не могут быть операнда-
ми команды XCHG.
К командам пересылки, работающим с аккумулято-
ром, относятся XLAT, IN, OUT (табл. 8.4). Команда XLAT
выполняет поиск в таблице и замену операнда на соответ-
ствующий байт из таблицы. Содержимое регистра AL ис-
пользуется в качестве индекса в 256-байтной таблице,
адресуемой регистром ВХ. Выбранный таким образом
однобайтный операнд пересылается в регистр AL. Команда
IN пересылает байт (или слово) из вводного порта в ре-
гистр AL (или АХ). Порт указывается либо байтом дан-
ных (доступ к портам от 0 до 255), либо номером порта в
регистре DX, допускающим обращение к 65536 портам вво-
да-вывода. Команда OUT работает подобно IN, но пере-
дача информации осуществляется из аккумулятора в
порт вывода.
К командам пересылки адресов относятся LEA, LDS,
LES (табл. 8.5). Команда LEA (загрузка исполнительно-
го адреса) передает смещение адреса в памяти, указанно-
го правым операндом, в общий регистр, регистр-указа-
тель или индексный регистр, указанный левым операндом.
Команда LDS (загрузить указатель в регистр DS) пере-
254
Таблица 8.4
Действие Мнемоника и формат Описание
Преобразователь Ввести: XLAT OPR (A)-((BX) + (AL))
короткая форма, байт IN AL, PORT (AL)-«-(PORT)
короткая форма, слово IN AX, PORT (AX)-<-(PORT-|- + 1:PORT)
длинная форма, байт IN AL, DX (AL)-«-((DX))
длинная форма, слово Вывести: IN AX, DX (AX)^((DX) + 1:(DX))
короткая форма, байт OUT PORT, AL (PORT) — ( AL)
короткая форма, слово OUT PORT, AX (PORT + + l:PORT)-<-(AX)
длинная форма, байт OUT DX, AL ((DX))-<-(AL)
длинная форма, слово OUT DX, AX ((DX) + 1:(DX))^(AX)
Таблица 8.5
Действие
Мнемоника и формат
Оп исание
Загрузить эффектив- LEA REG, SRC (REG)-«-SRC
ный адрес Загрузить в DS ука- LDS REG, SRC (REG)-<-(SRC);
затель Загрузить в ES ука- LES REG, SRC (DS)-<-(SRC-|-2) (REG)-<-(SRC);
затель (ES )-<-(SRC-|-2)
дает 32-битовый объект, содержащий смещение и сегмент
и хранящийся в виде двойного слова в памяти, в пару ре-
гистров. Адрес сегмента передается в регистр сегмента DS,
смещение — указанный 16-битовый общий регистр-указа-
тель или индексный регистр. Команда LES (загрузить
указатель в регистр ES) работает аналогично команде
LDS, за исключением того, что адрес сегмента помещает-
ся в регистр сегмента ES.
Существуют 4 команды пересылки битов условий
(табл. 8.6). Команда LAHF (загрузить регистр АН значе-
ниями битов условий) передает биты условий SF, AF, ZF,
PF и CF в регистр АН. Слово состояния МП PSW соот-
ветствует регистру признаков (флажков). Команда SAHF
(восстановить биты условий из регистра АН) передает
биты условий из регистра АН в одноразрядные регистры
255
Таблица 8.6
Действие Мнемоника Описание
Загрузить АН из флажков LAHF (АН) *- (младший байт PSW)
Запомнить АН во флажках SAHF (младший байт PSW)-<-(AH)
Включить в стек флаж^ ки PUSHF (SP)«-(SP) — 2; ((SP) + 1: (SP))«- 4-(PSW)
Извлечь из стека флажки POPF (PSW)4-((SP) + + 1.-(SP)): (SP)^(SP) —2
SF, ZF, AF, PF и CF. Команда PUSHF (засылка битов
условий в стек) уменьшает указатель стека SP на два и
пересылает все биты условий в два байта стека в соответ-
ствии с адресом, указанным в регистре SP. Команда POPF
(извлечение битов условий из стека) пересылает биты
условий из стека в соответствии с адресом, указанным в
регистре SP, в регистр битов условий и увеличивает ре-
гистр SP на 2.
8.2.2. АРИФМЕТИЧЕСКИЕ КОМАНДЫ
МП выполняет четыре основных математических дей-
ствия (с разнообразными модификациями) над 8- и
16-разрядными операндами по правилам арифметики с
учетом и без учета знака. Для чисел со знаком принято
стандартное представление в дополнительном коде. Опе-
рации сложения и вычитания чисел со знаком и без знака
различаются установкой битов условий. Они выполняются
над распакованными и упакованными десятичными чис-
лами. При реализации арифметических действий устанав-
ливаются 6 бит условий: CF, AF, ZF, SF, PF, OF. Суще-
ствуют пять команд сложения (табл. 8.7). Команда ADD
производит сложение операндов и запоминает результат
по адресу, задаваемому первым операндом. Команда ADC
производит сложение операндов и содержимого бита CF,
результат запоминается по адресу первого операнда. Ко-
манда INC увеличивает на 1 содержимое адресуемого эле-
мента и размещает результат по тому же адресу. Команда
DAA выполняет коррекцию числа в регистре AL, получен-
ного в результате сложения дв) х упакованных десятичных
операндов, при этом образуется vпакованная десятичная
256
Таблица 8.7
Дг ис гвие Мнемоника и формат Описание
Сложить ADD DST, SRC (DST)^-(SRC) + + (DST) Сложить с перено- ADC DST, SRC (DST)-<-(SRC) + com + (DST) + (CF) Инкремент INC OPR OPR-<-(OPR) + 1 Десятичная коррек- DAA (АЬ)-<-сумма в (AL) ция сложения корректируется в упако- ванный двоично-десятич- ный формат (BCD- формат) Коррекция неупа- АЛА (АЬ)-<-сумма в AL кованного BCD-сло- корректируется в неупа- жения кованный BCD-формат
сумма. Команда ААА выполняет коррекцию числа в реги-
стре AL, полученного в результате сложения двух распа-
кованных десятичных операндов, при этом образуется не-
упакованная десятичная сумма.
Существует семь команд вычитания (табл. 8.8). Коман-
да SUB производит вычитание из уменьшаемого, адресуе-
Таблица 8.8
Действие Мнемоника и формат Описание
Вычесть SUB DST, SRC (DST)^(DST) — ~(SRC) Вычесть с заемом SBB DST. SRC (DST)^(DST) — - (SRC) - (CF) Декремент DEC OPR OPR-<-(OPR) — 1 Изменить знак NEG OPR OPR-«-(OPR) Сравнить CMP OPR1, OPR2 (OPR 1) — (OPR2) Десятичная коррекция DAS (AL)-«-разность вычитания в (AL) корректирует- ся в упакованный BCD-формат Коррекция неупако- AAS (АН)-<-(АН) +пере- ванного BCD-вычитания нос от коррекции; • (AL) -«-разность в (AL) корректирует- ся в неупакованный BCD-формат мого первым операндом, вычитаемого, адресуемого вто-
рым операндом; результат записывается по адресу первого
операнда. Команда SBB производит вычитание из содер-
жимого, адресуемого первым операндом, содержимого,
адресуемого вторым операндом, и содержимого регист-
257
9 Скляров В. А.
pa CF. Команда DEC вычитает единицу из содержимого
адресуемого элемента и запоминает результат по тому же
адресу. Команда NEG производит вычитание содержимого
адресуемого элемента из нуля и размещает результат на
том же месте. Команда СМР производит вычитание, по-
добно команде SUB, устанавливает биты условий, но не
производит запоминания результата. Команда DAS вы-
полняет коррекцию результата вычитания двух упакован-
ных десятичных чисел и дает в результате упакованную
десятичную разность. Команда AAS осуществляет коррек-
цию числа в регистре AL, полученного в результате вы-
читания двух распакованных десятичных операндов,
и дает в результате распакованную десятичную раз-
ность.
Имеется три команды умножения (табл. 8.9). Команда
MUL производит умножение без знака содержимого акку-
Таблица 8.9
Деш тине Мнемоника и формат Описание
Умножить со знаком IMUL SRC Операнды — байты: (АХ )^- (AL)* (SRC); операнды — слова: (DX:AX)-«-(AX)*(SRC)
Умножить без знака MUL SRC Аналогична команде IMUL, но операнды и произведение беззна- ковые
Коррекция неупако- ванного ВС-умноже- ния ИМ (АН)-«-заем от коррек- ции; (АХ)-«-произведе- ние в AL корректируется в не\ пакованный BCD- формат. АН содержит старшую цифру
мулятора (AL или АХ) и содержимого, адцесуемого опе-
рандом, размещая результат двойной длины’ в аккумуля-
торе и его расширении (AL и АН для 8-разрядных операн-
дов, АХ и DX для 16-разрядных). Биты условий CF и OF
устанавливаются, если старшая половина результата не
равна пулю. Команда IMUL подобна MUL, но выполняет-
ся умножение с учетом знака. Биты услови й CF и OF уста-
навливаются, если старшая половина результата не явля-
ется расширением знакового бита младшей половины.
Команда ААМ производит коррекцию числа в регистре
АХ, полученного в результате умножения двух распако-
258
ванных десятичных операндов, и дает распакованное де-
сятичное произведение.
Имеются три команды деления и две команды формиро-
вания знака для операций деления со знаком (табл. 8.10).
Таблица 8.10
Действие Мнемоника и формат Описание
Разделить ID 1V SRC Делитель — байт: со знаком (AL)-«-частное (AX)/(SRC); (АН)-«-остаток (AX)/(SRC); делитель — слово: (АХ) -«-частное; (DX:АХ)/(SRC); (БХ)ч- остаток (DX.-AX)/ (SRC); частное и остаток имеют знаки, знак остатка равен знаку делимого Разделить без DIV SRC Аналогична команде LDLV, но знака операнды, частное и остаток беззнаковые Коррекция не- AAD (AL)-«—10ч (АН) -|- (AL); упакованного (АН)-<-0 BCD-деления Преобразовать CBW Расширяет знак AL в АН байт в слово Преобразовать CWD Расширяет знак АХ в DX слово в двойное слово
Команда DIV производит деление без знака содержимого
аккумулятора и его расширения (AL и АН для 8-разряд-
ной операции, АХ и DX для 16-разрядной) на содержимое,
адресуемое операндом, и размещает частное в аккумуля-
торе (AL или АХ) и остаток одинарной длины в расшире-
нии аккумулятора (АН или DX). Биты условий не опреде-
лены. Деление на нуль дает прерывание по вектору 0.
Команда IDIV работает подобно команде DIV, за исклю-
чением того, что она производит деление с учетом знака.
Команда AAD производит коррекцию делимого в регистре
AL перед делением двух распакованных десятичных опе-
рандов, так что в результате получится распакованное
десятичное частное. Команда CWB выполняет распростра-
нение знака числа в регистре AL на регистр АН, т. е. преоб-
разование байта в слово. Команда CWD осуществляет
распространение знака числа в регистре АХ на регистр DX,
т. е. преобразование слова в двойное слово.
259
8.2.3. Логические команды
Основные логические действия выполняются как над
8-, так и 16-битовыми операндами. Форматы команд сдви-
гов приведены в табл. 8.11. Четыре команды сдвига вы-
полняются над содержимым памяти или регистров: SHL,
SHR, SAL, SAR. Первые две команды осуществляют логи-
Таблща 8.11
Действие Мнемоника и формат Описание
Сдвинуть логически влево SHL OPR, CNT
Сдвинуть арифметически SAL OPR, CNT
влево
Сдвинуть логически впра- во SHR OPR, CNT
Сдвинуть арифметически SAR OPR, CNT
вправо
Сдвинуть циклически ROL OPR, CNT
влево
Сдвинуть циклически ROR OPR, CNT
вправо
Сдвинуть циклически вле- во через перенос RCL OPR, CNT
Сдвинуть циклически вправо через перенос RCR OPR, CNT
ОРЯ
Аналогична SHL
ческий сдвиг, вторые — арифметический. Возможны сдви-
ги на один бит и на переменное число битов, указанное в
регистре CL. Бит CF становится равным последнему
сдвигаемому биту; бит OF изменяется только для сдвигов
на один разряд и устанавливается в том случае, если бит
знака результата операции отличается от первоначально-
го значения бита знака. Биты PF, SF, ZF устанавливаются
в соответствии со значением результата. Четыре команды
циклического сдвига с использованием бит^СБ подобны
командам сдвига и выполняются над содержимым памяти
или регистров: ROL, ROR, RCL, RCR.
Существуют четыре логические команды над двумя
операндами. В них биты CF и OF сбрасываются, а биты
SF, PF, ZF отражают результат выполнения операции.
Команда NOT производит операцию инвертирования со-
держимого, адресуемого полем операнда, и возвращает
результат на то же место. Биты условий не изменяются.
Команда AND производит поразрядное логическое умно-
жение операндов и размещает результат по адресу, зада-
260
ваемому первым операндом. Команда OR выполняет по-
разрядное логическое сложение операндов и размещает
результат по первому адресу. Команда XOR выполняет
поразрядное логическое сложение по модулю 2 операндов
и размещает результат по первому адресу. Команда
TEST выполняет то же действие, что и AND; она
устанавливает биты условий, но не формирует результат.
Логические команды приводятся в табл. 8.12.
Таблица 8.12
Действие Мнемоника и формат Описание
Инвертировать
Объединить по И
Объединить по ИЛИ
Сложить по модулю 2
(Исключающее ИЛИ)
Проверить
NOT OPR
AND DST, SRC
OR DST, SRC
XOR DST, SRC
TEST OPRI, OPR2
(OPR)-<-NOT(OPR)
(DST)-<-(DST) AND
(SRC)
(DST)-<-(DST) OR
(SRC)
(DST)-<-(DST)
XOR(SRC)
(OPRI) AND (OPR2)
8.2.4. Команды работы co строковыми данными
Однобайтные команды выполняют простейшую обра-
ботку строк байтов и слов. Элементарные действия над
байтами могут быть многократно выполнены, если команде
предшествует префикс-повторитель. Команды могут объе-
диняться для выполнения сложных действий над
строками. Тогда повторение обеспечивается итерацией.
Все элементарные операции над строками используют
регистр SI для адресации операнда-источника. Регистр DI
применяется для адресации результата, который находит-
ся в дополнительном сегменте. Если бит DF сброшен, со-
держимое индексных регистров увеличивается после каж-
дой операции над байтами на единицу и на два после опе-
рации над словами. Если установлен бит DF, содержимое
индексных регистров операнда и результата уменьшается
после каждой операции. Каждой элементарной строковой
команде может предшествовать однобайтовый префикс,
указывающий, что команда должна повторяться до тех
пор, пока счетчик в регистре СХ не будет установлен в
нуль. Проверка содержимого счетчика выполняется до
повторения операции. Если содержимое счетчика в регист-
ре СХ равно нулю, операция выполняться не будет. Пре-
фикс повторения определяет также величину, которая
должна сравниваться с битом ZF. Если элементарная ко-
261
манда воздействует на бит ZF и его значение не равно
обозначенной величине после очередного выполнения опе-
рации, ее повторение прекращается. Это позволяет органи-
зовывать цикл типа DO — WHILE.
Во время выполнения повторяющейся элементарной
команды индексные регистры SI, DI и счетчик повторений
(СХ) изменяются после каждого повторения, а счетчик
команд будет по-прежнему содержать смещение байта
префикса (в предположении, что он непосредственно
предшествует команде над строками). Прерванная коман-
да над строками будет правильно продолжена после воз-
вращения управления из прерывающей программы, если
перед элементарной командой расположен только один
префикс. Поэтому следует избегать использования двух
других префиксов совместно с префиксом-повторителем в
командах работы со строками, т. е. префикса сегмента и
префикса LOCK. Это связано с тем, что после выхода из
прерывающей программы выполнение возобновится с
адреса, на байт меньшего адреса команды (т. е. адреса,
в котором предположительно расположен префикс-повто-
ритель), а дополнительные префиксы будут проигно-
рированы.
Существуют пять элементарных команд работы со стро-
ками. Команда MOVS пересылает байт (слово) из поля,
указываемого вторым операндом, в поле, задаваемое пер-
вым операндом. В случае итеративного использования
команды она предназначена для пересылки строк из одной
области памяти в другую. Команда CMPS производит вы-
читание байта (слова), адресуемого вторым операндом,
из байта (слова), адресуемого первым операндом. Коман-
да воздействует на биты условий, но не формирует резуль-
тат. Она предназначена для сравнения строк. При соответ-
ствующем префиксе-повторителе можно определить, после
какого элемента две строки начинают отличаться друг от
друга, и, таким образом, установить порядок, в котором
они должны располагаться. Команда SCAS вычитает байт
(или слово), адресуемый операндом, из регистра AL (или
АХ), воздействует на биты условий, но не формирует ре-
зультата. В случае итеративного использования команду
можно применять для поиска вхождения некоторой вели-
чины в строку. Команда LODS пересылает байт (или сло-
во), адресуемый операндом, в регистр AL (или АХ). Обыч-
но эта команда не использует префикс-повторитель. Ко-
манда STOS пересылает байт (или слово) из регистра AL
(или АХ) в поле, адресуемое операндом. При здании пре-
262
фикса-повторителя она может использоваться для запол-
нения строки определенной величины. Форматы строко-
вых команд и префиксов повторения сведены в табл. 8.13
и 8.14.
Таблица 8.13
Деист вне Мнемоника и формат Описание
1 2 3
Передать цепочку MOVS DST, SRC ((DI)) - - ((SI)); опер анды-байты: (SI)-(SI) + 1, (Dl)-(DI) +1; операнды-слова: (SI) — (SI) +2, (l)I)-(Dl) +2
Передать цепочку бай- тов MOVSB
Передать цепочку слов MOVSW
Сравнить цепочки CMPS SRC, DST ((SI) —((DI); операнды-байты: (SI) —(SI) + I, (Dl)-(Dl) +1; операнды-слова: (SI)-(SI) +2, (DI)-(DI) +2
Сравнить цепочки бай- тов CMPSB
Сравнить цепочки слов CMPSW
Сканировать цепочку SCAS DST Операнд-байт: (AL) —((DI)), (DD—(DI) + I; операнд-слово: (AX) —((DI)), (DI) —(DI)+2
Сканировать цепочки байтов SCASB
Сканировать цепочки слов SCAW
Загрузить цепочку LODS SRC Операнд-байт: (AL)-((SI)), (SI)-(SI) + 1; операнд-слово:
Загрузить цепочку бай- тов (AX) —((SI)), (SI)^(SI) +2
LODSB
Загрузить цепочку слов LODSW
Запомнить цепочку STOS DST Операнд-байт: ((DI) —(AL),
263
Окончание табл. 8.13
(DI)^(D!) + I;
операнд-слово:
((D !))-<-(AX'),
(DI)-<-(DI) 4-2
Запомнить цепочку
байтов
Запомнить цепочку
слов
STOSB
STOSW
Таблица 8.14
Действие Мнемо ника Назначение Проверяемое условие
Повторять цепочечную REP Цепочечный (СХ)=0
операцию до СХ=0 примитив
Повторять цепочечную REPE Цепочечный (СХ) = 0 или
операцию, пока равно или ИЛИ примитив (ZF) =0
не нуль REPZ
Повторять цепочечную REPNE Цепочечный (СХ) = 0 или
операцию, пока не равно ИЛИ примитив (ZF) = [
или не нуль REPNZ
8.2.5. Команды передачи управления
Можно выделить четыре класса команд передачи
управления: 1) вызовы подпрограмм, переходы и возвра-
ты из подпрограмм (табл. 8.15); 2) условные переходы
(табл. 8.16); 3) команды передачи управления для форми-
рования циклов (табл. 8.17); 4) вызовы программ преры-
вания (табл. 8.18).
Все эти команды вызывают выполнение программы с
некоторого нового адреса в памяти (возможно, и в другом
сегменте). Условные переходы осуществляются в диапа-
зоне от — 128 до 4-127 байт от точки передачи управления.
Существуют две разновидности команд вызова, перехода
и возврата: команды, передающие управление в пределах
текущего сегмента кода, и команды, передающие управле-
ние в любой сегмент кода, который затем становится те-
кущим. Возможны переходы как прямые, так и косвенные.
По команде CALL смещение адреса следующей команды
помещается в стек (в случае межсегментного вызова пер-
вым засылается регистр сегмента CS), а потом управление
передается в любой сегмент программы, который затем
становится текущим. По команде JMP управление пере-
дается по адресу, задаваемому операндом. По команде
264
Таблица 8.15
Действие Мнемоника и формат Описание
Внутрисегментный пря- ой вызов CALL DST (SP)4-(SP) — 2; ((SP) + l-.(SP) )^(1P); (IP)4-(IP) + D16
Внутрисегментный кос- венный вызов CALL DST (SP)4-(SP) — 2; ((SP) + [ ;(SP) )-<-(IP)-, (IP)^(EA)
Межсегментный прямой вызов CALL DST (SP)^(SP) -2; ((SP)-H:(SP))-<-(CS); (SP)4-(SP)-2; ((SP) + [ :(SP)) ^(IP); (!P)-«-D[6; (CS)-«-сегментный адрес
Межсегментный косвен- ный вызов CALL DS1 (SP)^(SP) -2; ((SP) + [:(SP))^(CS); (SP)-<-(SP) — 2; ((SP) -H:(SP))^(IP); (IP)^(EA); (CS)-<-(EA-|-2)
Внутрисегментный возврат RET (IP)-«-((SP)-p I:(SP)); (SPN-(SP) J-2
Внутрисегментный воз- врат с непосредственными данными Межсегментный возврат RET EXP RET Аналогична предыдущей команде и (SP)-<-(SP) -|- + DI6; (IP)^((SP)+1:(SP)); (SP)4-(SP) -2; (CSH-(SP) + I:(SP)); (SP)^(SP)+2
Межсегментный возврат с непосредственными дан- ными RET EXP Аналогична предыдущей команде и (SP)-<-(SP)+ J-DI6
Внутрисегментный пря- мой короткий переход JMP SHORT OPR (IP) -«—(IP) + 8-битовое смещение, определяемое OPR
Внутрисегментный пря- мой близкий переход JMP NEAR PTR OPR (IP)-«—(IP) J- !6-битовое смещение, определяемое OPR
Внутрисегментный пря- мой косвенный переход JMP OPR (!Р)*-(ЕА), где ЕА опре- деляется OPR
Межсегментный прямой далекий переход Межсегментный косвен- ный переход JMP FAR PTR (!P)-«-смещение OPR в OPR сегменте; (СЗ)^адрес сегмента, со- держащего OPR JMP OPR (!P)*-(EA), где EA опре- деляется OPR; (CS)^(EA + 2)
265
Таблица 8.16
Действие Мнемоника и формат Альтернатив- ная мнемо- ника Проверяемое условие
Перейти, если нуль или равно JZ OPR JE ZF =!
Перейти, если не нуль или не равно JNZ OPR JNE ZF=0
Перейти, если знак ,TS OPR S Г= [
установлен
Перейти, если знак сброшен JNS OPR SF = ()
Перейти, если есть JO OPR OF = [
переполпение Перейти, если нет переполнения JNO OPR OF = 0
Перейти, если пари- JP OPR JPE PF= [
тет установлен (чет- ный паритет) Перейти, если пари- тет сброшен (нечет- ный паритет) JNP OPR JPO PF = 0
Перейти, если ни- JB OPR JNAE, JC CF= !
же/не выше или равно (без знака)
Перейти, если не JNB OPR JAE, JNC CF = 0
ниже/выше или равно (без знака) Перейти, если ниже или равно/не выше (без знака) JBE OPR JNA ((CF)OR (ZF)) = I
Перейти, если ие ниже или равно/выше (без знака) JNBE OPR JA ((CF)OR(ZF) =0
Перейти, если мень- ше/ие больше или JL OPR JNGE ((SF) XOR (OF)) = I
равно (со знаком)
Перейти, если не JNL OPR JGE ((CF)XOR (OF)) =0
меньше/больше или равно (со знаком)
Перейти, если мень- ше (((SF)XOR (OF)) OR (SF)) — I или рав- но/не больше (со зна- ком) JLE OPR JNC
Перейти, если не JNLE OPR JG (((SF)XOR(OF)))
меньше или равно/ больше (со знаком) OR(ZF)) =0
266
Таблица 8.17
Де йствие Мнемоника н формат Лл ьтернатив- ная мнемо- ника Проверяемое условие
Заци клить LOOP OPR (СХ) не равно
Зациклить, пока не LOOPZ OPR LOOPE нулю ZF—1 и (СХ) не
нуль или равно Зациклить, пока не LOOPNZ OPR LOOPNE равно нулю ZF = 0 и (СХ) не
нуль или не равно Перейти по СХ JCXZ OPR равно нулю (СХ) =0
Таблица 8.18
Действие Мнемон пка и формат Описание
Прерывание с типом INT TYPE (SP)t-(SP) -2; ((SP) + 1:(SP))-(PSW); (SP)^-(SP) -2; ((SP) + I:(SP))-(CS); (SP)-(SP) 2; ((SP) + 1:(SP))-(IP), (IP)(TYPE*4);‘ (CS)-(TYPE*4 + 2)
Однобайтное прерывание INT Аналогична предыдущей, кроме TYPE = 3
Прерывание при переполне- нии INTO (SP)^-(SP) — 2; ((SP) -|-I: (SP)) -(PSW); (SP)-(SP) -2; ((SP) + l:(SP))->-(CS); (SP)-HSP) -2; ((SP) + 1:(SP))-(IP); (IP)-<-( 10H), (CS'->-(12H)
Возврат из прерывания IRET (IP)-((SP) + 1:(SP)), (SP)-(SP) +2; (CS)-((SP) + 1:(SP)); (SP)<-(SP)-p 2; (PSW)->-((SP)-f-1:(SP)) (SP)-(SP) +2
RET управление передается из вызываемой подпрог-
раммы в основную и, если необходимо, восстанав-
ливается регистр SP, если в стек были помещены пара-
метры.
Прямые вызовы и переходы в пределах сегмента со-
держат смещение относительного перехода и, таким об-
разом, дают позиционно независимый код. Сокращенная
267
форма команд перехода допустима в диапазоне от — 128 до
+ 127. Для команд условных переходов условия «выше»
или «ниже» относятся к величинам без знака, а «больше»
и «меньше» — к величинам со знаком. Операторы пере-
дачи управления для формирования циклов осуществляют
контроль за их выполнением. Оператор, на который пере-
дается управление, должен отстоять от команды, управ-
ляющей циклом, на число байтов от — 128 до + 127.
Существуют четыре циклические команды передачи
управления. Команда LOOP уменьшает счетчик в регистре
СХ на единицу и передает управление, если его содержи-
мое не равно нулю. Команда LOOPZ (она еще называется
LOOPE) уменьшает содержимое регистра СХ на единицу
и передает управление, если содержимое счетчика не равно
нулю и бит ZF установлен (цикл «пока 0», или цикл «пока
равно»). Команда LOOPNZ (или LOOPNE) уменьшает
содержимое регистра СХ на 1 и передает управление, если
содержимое СХ не равно нулю и бит ZF сброшен (цикл
«пока не 0» или цикл «пока не равно»). Команда JCXZ
передает управление, если содержимое регистра СХ рав-
но нулю.
Управление может передаваться посредством команд,
подобных по своему действию внешним прерываниям. Все
прерывания осуществляют передачу управления путем
записи регистра битов условий в стек (как по команде
PUSHF) с последующим межсегментным вызовом через
элемент вектора прерываний. Существуют три команды пе-
редачи управления такого типа. По команде INT биты
условий помещаются в стек, биты TF и IF сбрасываются,
и управление передается посредством косвенного вызова
по одному из 256 векторов прерываний. Для прерываний
по вектору 3 возможна однобайтная форма этой коман-
ды. По команде INTO биты условий помещаются в стек,
и управление передается посредством косвенного вызова
по вектору 4, если установлен бит OF (прерывание по
переполнению); если бит OF сброшен, никаких действий не
производится. По команде IRET управление передается по
адресу возврата, сохраненному при выполнении последней
команды прерывания, и восстанавливается содержимое
битов условий.
8.2.6. Команды управления МП
Существуют различные команды для проверки состоя-
ния МП и выполнения операций, а также взаимодействия
268
МП с внешней средой. Есть семь кома *д, работающих
непосредственно с битами условий (табл. 8.19): команда
CLC сбрасывает бит CF; команда СМС инвертирует бит
CF; команда STC устанавливает бит CF; команда CLD
Таблица 8.19
Действие Мнемоника Описание
Сбросить перенос CLC CF--0
Инвертировать перенос СМС CF-e-NOT(CF)
Установить перенос STC CF--1
Сбросить направление CLD DF--0
Установить направление STD DF-<-l
Сбросить прерывание CLI IJ'-O
Установить прерывание STI JF-e-1
сбрасывает бит DF, что ведет к автоувеличению
указателей операндов при строковых операциях; ко-
манда STD устанавливает бит DF, что ведет к
автоуменьшению указателей операндов при строковых
операциях; команда CLI сбрасывает бит IF, запрещая
внешние прерывания (кроме немаскируемых внешних
прерываний); команда STI устанавливает бит IF, разре-
шая внешние прерывания после выполнения следующей
команды.
Команда HLT (табл. 8.20) переводит МП в состояние
останова, из которого он выходит по разрешению внеш-
Таблица 8.20
Действие Мнемоника Описание
Холостая операция NOP Не вызывает никаких действий
Остановить HLT Прекращает действия ЭВМ
Переключить ESC Подключает сопроцессор
Ждать WALT Ожидает активного уровня сиг-
нала на входе TEST
него прерывания или по сигналу начальной установки.
Команда NOP не вызывает никаких действий и выполняет-
ся за 2 такта синхронизации. По команде WAIT МП пе-
реходит в состояние ожидания, которое может быть на-
рушено внешним прерыванием. В этом случае сохранен-
ный адрес будет адресом команды WAIT, поэтому после
возврата из прерывающей задачи состояние ожидания
будет возобновлено. Состояние ожидания сбрасывается
и продолжается выполнение программы, если подтвер-
ждается сигнал TEST. При возобновлении выполнения
269
внешнее прерывание запрещается, пока не будет выпол-
нена следующая команда. WAIT позволяет синхронизи-
ровать процессор с внешним устройством. Команда ESC
обеспечивает механизм, благодаря которому другие про-
цессоры могут воспринимать команды из потока команд
МП и использовать его методы адресации. По команде
ESC МП не выполняет никаких действий, кроме осуществ-
ления доступа к операндам в памяти. Если установлен
бит TF, МП генерирует прерывание по вектору 1 после
выполнения каждой команды. Это позволяет работать в
пошаговом режиме в процессе отладки.
Во время обработки прерываний любого типа бит TF
сбрасывается после сохранения битов условий в стеке. Ко-
манд для непосредственной установки или сброса бита TF
не существует. Поэтому образ битов условий, сохраненный
в стеке предыдущей командой прерывания, должен быть
изменен так, чтобы последующий возврат из прерывания
был выполнен с восстановленным битом TF. Если же
команда, выполненная в пошаговом режиме, генерирует
прерывание или поступает внешний запрос до заверше-
ния команды, прерывание по вектору 1 возникает после
запроса, генерируемого командой или устройством, но
перед первой командой программы обработки прерываний.
8.3. БАЗОВЫЕ КОНСТРУКЦИИ ЯЗЫКА
Алфавит допустимых символов языка ассемблера
включает прописные и строчные буквы латинского алфа-
вита (они не различаются), цифры, непечатаемые знаки,
такие, как пробел, табуляция, возврат каретки, перевод
строки, и специальные символы (ф- — * / = ( ) [ ] О ;
Минимальный элемент программы — это лексема, со-
стоящая из нескольких символов. Чаще всего лексема
представляет собой имя, отличающееся от все£ остальных
имен первыми 31 символами, остальные символы игнори-
руются. Зарезервированные слова — это имена, имеющие
заранее определенное значение (мнемонические имена
регистров микропроцессора, мнемонические коды опера-
ций и т. д.). Имена можно подразделять на группы:
имена регистров, имена переменных, метки, имена конс-
тант, другие имена (сегментов, групп, записей, полей за-
писей, формальных параметров). Для разграничения имен
используются разделители (табл. 8.21), простейшими из
которых являются пробел и горизонтальная табуляция.
270
Таблица 8.21
Символ Название Назначение
Двоеточие Разделитель для меток, префиксов сегмен- тов, определенных извне данных, определи- телей полей записей
Точка Разделитель поля и записи; допустим только в макрокомандах
& Амперсанд Признак строки продолжения оператора
<•••> Пара угло- вых скобок Указывает на то, что заключенная в них величина используется для инициализации записей в макрокомандах
Знак де- нежной еди- ницы Сокращенное обозначение для счетчика команд
[...] Пара квад- ратных скобок Ограничивает выражение для регистров индекса или указателя
= Равенство Признак определителя длины поля
— Минус Знак вычитания, или унарный минус
+ Плюс Знак сложения, или унарный плюс
* Звездочка Знак умножения
/ Косая черта Знак деления
Знак вопро- са Указывает, что присвоение начального значения области памяти не производится
Ком мерче- ское ЭТ Используется для формирования имен
— Знак под- черкивания Используется для формирования имен
1—1 Пробел Разделитель полей оператора
Запятая Разделитель операндов, а также макро- параметров в поле операндов
Кавычки Ограничитель строки символов
Круглые скобки Ограничитель выражения
ввод Возврат ка- ретки Ограничитель оператора языка
Точка с за- пятой Используется для указания поля ком- ментариев
Исходный модуль любой программы на ассемблере
представляет собой последовательность операторов языка,
занимающих обычно по одной строке. Все операторы мож-
но разделить на две группы: исполняемые и неисполняе-
мые. Исполняемые операторы транслируются в машинные
коды и всегда содержат мнемонику команды, а также до
двух операндов. Неисполняемые операторы (их чаще на-
зывают директивами) предназначены для распределения
памяти, описания сегментов, процедур, формирования
структур данных и управления процессом трансляции.
Ниже изображен общий формат ассемблерной команды,
271
который но быть включает пять полей; поле кодо в операций долж- менее чем одним
отдельно от поля операндов не
пробелом:
LAWEL: LOCK MOV DS,AX ;загрузка сегментного регистра
поле поле поле поле поле комментариев
меток префикса кодов операций операндов
Метка представляет собой определяемое пользовате-
лем имя (идентификатор), присваиваемое первому байту
команды, у которой она появляется. Команда может иметь
один или несколько префиксов: замены сегмента, блоки-
ровки LOCK или повторения REP. Все команды должны
иметь мнемонику, которая является зарезервированным
именем. Наличие операндов зависит от команды. В качест-
ве операнда могут использоваться символы, константы,
выражения. Ограничивается поле точкой с запятой (;)
или возвратом каретки. В случае двух операндов они раз-
деляются запятой. Поле комментариев может содержать
любой набор символов; наличие его не обязательно. При-
знаком начала комментария является точка с запятой (;).
Наличие метки не обязательно, но если она есть, то
становится символическим именем, которое может примё-
няться в командах переходов. Метка характеризуется че-
тырьмя атрибутами; 1) сегментом, в котором она опре-
делена; 2) смещением; 3) расстоянием; 4) содержимым
регистра CS. Расстояние может быть типа NEAR или
FAR. Тип NEAR означает, что при обращении к метке
используется только смещение и во всех командах пере-
хода будет сгенерирован ассемблером один из режимов
внутрисегментного перехода. Все метки по умолчанию
имеют тип NEAR. При обращении к метке с атрибутом
расстояния FAR необходимо изменять как счетчик команд
IP, так и регистр CS, т. е. генерировать межсегментный
переход. Заметим, что если хотя бы одно обращение к
метке происходит из другого сегмента, то она обязательно
должна иметь тип FAR. Метка дополнительно опреде-
ляется следующими способами: именем в директиве
LABEL; именем в директиве EQU; именем в соответствую-
щих друг другу директивах PROC/ENDP.
Ассемблер использует числа в четырех системах счисле-
ния. Каждая из них определяется буквой, которая сле-
дует за числом: В — двоичное число; О — восьмеричное;
D — десятичное; Н — шестнадцатеричное. Буква D для
идентификации десятичного числа может быть опущена.
272
Если шестнадцатеричное число начинается с буквы, для
его отличия от символов вводится первый нуль. Перед
отрицательными числами ставится знак минус (—). Вы-
ражения состоят из числовых констант и/или текстовых
символов, которые могут быть связаны между собой сле-
дующими операторами: + (сложение); —(вычитание);
♦ (умножение); /(деление); MOD (модуль); SHL (сдвиг
влево); SHR (сдвиг вправо); NOT (отрицание); AND
(конъюнкция); OR (дизъюнкция); XOR (Исключающее
ИЛИ). Выражения могут заключаться в круглые скобки.
Операнды должны отделяться минимум одним пробелом
от символов операций MOD, SHL, SHR, NOT, OR, XOR.
Результат вычисления выражения должен находиться
в допустимом диапазоне чисел (от 0 до ±FFFF). Выра-
жения в языке ассемблера бывают двух видов: числовые
и адресные. Для последних в качестве операндов исполь-
зуются переменные и метки. Адресные выражения служат
для присваивания начальных значений.
Важнейшие директивы ассемблера приведены в табл.
8.22. EQU определяет новый идентификатор. Однако в
Таблица 8.22
Директив а Назначение
1 2
ASSUME COMMENT DB Связывает имя сегмента с регистром сегмента Позволяет ввести комментарий, не используя символ; Определяет и резервирует требуемое число байтов па- мяти
DW Определяет и резервирует требуемое число стандартных слов памяти
DD Определяет и резервирует требуемое число двойных СЛОВ
DQ Определяет и резервирует требуемое число слов памяти
DT четырехкратной длины Определяет и резервирует требуемое число 10-байтных участков памяти
END ENDP ENDS EQU Определяет конец текста программы на ассемблере Определяет конец процедуры Определяет конец сегмента или структуры Ставит в соответствие символическому имени значение выражения
= Ставит в соответствие символическому имени значение
EVEN EXTRN выражения в различных местах программы Выравнивает счетчик адресов ячеек по границе слова Описывает символические имена, определенные в другом
GROUP модуле Используется для объединения сегментов с целью до- ступа к ним через один сегментный регистр
273
Окончание табл. 8.22
1 2
INCLUDE LABEL При трансляции подключает текст из другого файла Приписывает символическому имени указанные атри- буты
MACRO NAME ORG PROC Определяет макрокоманду Задает имя модуля Переопределяет текущее значение счетчика адресов Определяет имя блока программы, обычно вызываемого по команде CALL
PUBLIC Определяет символические имена, на которые можно ссылаться в других модулях
SEGMENT TITLE Объявляет сегментом группу операторов Определяет заголовок, который должен быть распеча- тан на каждой странице листинга
LOCAL Создает уникальный символ для каждого фиктивно- го параметра макрокоманды
данном случае новое имя получают и атрибуты выраже-
ния его операнда. Директивы DB, DW и DD определяют
данные, для представления которых требуется байт, слово
и двойное слово. Они используются для описания констант,
значения которых устанавливаются во время загрузки
программы, и переменных, которым начальные значения
не присваиваются. Операнд ? является признаком пере-
менной, начальное значение которой не определено. Если
директива резервирования памяти имеет несколько опе-
рандов, они разделяются запятыми. Любой операнд может
быть повторен п раз посредством заключения его в круглые
скобки и записи перед этой конструкцией п DUP. Различ-
ные способы использования директив резервирования и
определения памяти приведены ниже:
; Примера определима байта
Byte DB ’ ; Иеопредехевиое вачахьвое ; звачевве
ConstB DB 34 ; Дееатнчнап ковставта
Char DB ; CuBoibaai константа
PaekedBCD DB 120,340,560,780 ; Васю 12345678 в упаковавво»;
Unpacked DB 8,7,6,5,4,3,2,1 ; двсвчио-дееатвчком формате ; Внсю 87654321 в иеупаковаяяои
String DB 'dd'.’.'ss' ; двовчво-десатвчном формате ; Провзвохьаав строка
Text DB 'Be гогов !' ; Сообщение
; Пркиера String# опредехеш схова OUG 1060 DB 2,8888,11001b ; Установка сяеаеивз ; Провзвохьнаа строка
T»oChar D# 'Bl' ; Возвоаво топко два сихвока
Adr DB Adr ; Иаацкаакзацаи смецеинем Adr
Distanse D# TeoChar-Byte? ; Разность двум смеденмй
; Пример опредешш двойного сива
DefHEl DD Adr ; Сиво содернт дказатедь га Adr
274
Каждая переменная или метка имеет определенный
тип: BYTE PTR — значением идентификатора является
16-битовое смещение для переменной, занимающей в па-
мяти один байт; WORD PTR — значением идентификатора
является 16-битовое смещение для переменной, занимаю-
щей в памяти одно слово; DWORD PTR — значением
идентификатора является 16-битовое смещение для пере-
менной, занимающей в памяти два слова; NEAR PTR —
значением идентификатора является 16-битовое смещение
для метки, переход на которую может быть выполнен
с помощью внутрисегментных команд перехода и вызо-
ва подпрограмм; FAR PTR — значением идентифи-
катора является 16-битовое смещение для метки, переход
на которую может быть выполнен с помощью меж-
сегментных команд перехода и вызова подпрограмм;
NUMBER — значением является произвольное 16-раз-
рядное число.
Напомним, что любому идентификатору соответствует
некоторое имя сегмента. При анализе типов идентифика-
торов ассемблер может контролировать корректность ко-
манд, написанных программистом. Здесь имеется в виду
проверка соответствия типов операндов и устранение дву-
смысленности в командах вида INC [ВХ]. Кроме того,
ассемблер имеет встроенные операторы преобразования
типов (табл. 8.23), воздействующие только на тот иденти-
фикатор, перед которым они встречаются. Например, по
команде MOV DX, OFFSET VAR в регистр DX будет за-
гружено смещение переменной VAR.
Таблица 8.23
Оператор Из типа В тип Примечание
OFFSET PTR NUMBER Смещение в сег- менте
SEG PTR NUMBER Базовый адрес сегмента
SIZE Данные типа PTR NUMBER Число байтов, выделенных для данных
LENGTH Данные типа PTR NUMBER Число байтов слов, двойных слов
BYTE PTR PTR или NUMBER BYTE PTR
WORD PTR PTR или NUMBER WORD PTR Имя сегмента не
DWORD PTR PTR или NUMBER DWORD PTR >изменяется
NEAR PTR PTR или NUMBER NEAR PTR
FAR PTR PTR или NUMBER FAR PTR
275
Микропроцессор обеспечивает возможность разбиения
программ на четко определенные модули: программные,
данных и стековые. Каждый модуль может располагаться
в отдельном логическом сегменте, доступ к которому обе-
спечивается с помощью соответствующего сегментного
регистра. Традиционно программы пользователя состоят
из трех логических сегментов: кода, данных и стека. В наи-
более общем случае отдельно взятый исходный модуль
может быть сегментом, частью сегмента, состоять из не-
скольких сегментов или комбинировать все эти возмож-
ности.
Для определения начальной и конечной ячеек логи-
ческого сегмента предусмотрены директивы SEGMENT и
ENDS. Все команды и/или данные, расположенные между
директивами SEGMENT и ENDS, образуют логический
сегмент программы. Директива SEGMENT имеет следую-
щий синтаксис:
(имя) SEGMENT [{тип выравн.)] [{тип связ.)] [{’имя класса’)]
{имя> ENDS
Е1араметр (имя) должен быть уникальным допустимым
именем сегмента. Необязательный параметр (тип вы-
равн.) сообщает компоновщику, с какой границы должен
начинаться сегмент, и может быть следующих типов:
PAGE — сегмент начинается с адреса вида ХХХООН, т. е.
значение младшего байта физического адреса равно 0;
PARA — сегмент начинается с адреса вида ХХХХОН, т. е.
значение младшего полубайта равно 0; этот тип действует
по умолчанию и означает выравнивание на границу пара-
графа (заметим, что для типов PAGE и PARA смещение
первого элемента сегмента всегда равно 0); WORD —
сегмент начинается с адреса вида ХХХХеН, где е означает
четное число, и тогда смещение первого элемента сегмента
всегда будет четное, но не обязательно нулевое; BYTE —
сегмент начинается с адреса вида ХХХХХН, Е. е. с любого
адреса. Необязательный параметр (тип связ.) сообщает
компоновщику, как организуются друг относительно друга
сегменты данного класса. Если этот тип не указан, сегмен-
ты загружаются по отдельности и имеют свои базовые
адреса.
Программист может связывать сегменты (т. е. указы-
вать их абсолютное или относительное расположение в
памяти) с помощью следующих ключевых слов: PUBLIC—
сегменты, имеющие общее имя и общее имя класса, распо-
лагаются в памяти одним непрерывным блоком, причем
276
для всех сегментов типа PUBLIC существует только один
базовый адрес, а смещение берется от начала первого
сегмента для всех сегментов группы; STACK — органи-
зация сегментов подобна PUBLIC, однако указатель стека
установлен на базовый адрес первого стекового сегмента;
компоновщик требует наличия в программе хотя бы одного
стекового сегмента; COMMON — сегменты, имеющие
общее имя и общее имя класса, располагаются в памяти,
перекрывая друг друга; для всех сегментов типа COMMON
с общим именем существует только один базовый адрес.
Область памяти, занимаемая сегментами, равна размеру
наибольшего из них; MEMORY — сегменты с таким типом
организации располагаются в области старших адресов
памяти. В программе должен быть только один сегмент
типа MEMORY, так как компоновщик учитывает этот тип
связывания только у первого сегмента. Следующие за ним
сегменты рассматриваются как сегменты с организацией
типа COMMON, и компоновщик выдаст предупреждаю-
щее сообщение; АТ (выр.) — сегмент располагается по
адресу типа PARA, указанному в выражении, что позво-
ляет программисту задать начальный адрес логического
сегмента, т. е. определять переменные и метки по фиксиро-
ванным смещениям в пределах фиксированных областей
памяти. Этот тип не может быть использован для загрузки
по фиксированным адресам, а выражение не может быть
ссылкой вперед. Необязательный параметр (’имя класса’)
должен быть любым допустимым именем, заключенным в
апострофы.
Класс — это набор сегментов. Сегменты определен-
ного класса загружаются в память последовательно и
располагаются в том порядке, в котором компоновщик
встречает их в объектных модулях. Если сегмент одного
класса во входных данных компоновщика предшествует
всем сегментам другого класса, первый класс распола-
гается в памяти перед другим. Программист может управ-
лять порядком следования классов в памяти путем написа-
ния фиктивного модуля, в котором объявляются сегменты
по классам в порядке загрузки классов, и указания его
первым из объектных модулей. Определения сегментов
допускают вложения, однако ассемблер всегда трансли-
рует сначала полностью внешний сегмент, игнорируя
вложенный, и только при достижении директивы ENDS
переходит к трансляции вложенного сегмента. Пересече-
ния сегментов не допускается.
Иногда возникает необходимость адресовать несколько
277
сегментов с помощью одного базового адреса. Програм-
мист может реализовать такое объединение различных
сегментов в виде групп. Группа — это несколько сегмен-
тов, разделяющих (коллективно использующих) общую
базу и занимающих не более 64 К байт памяти. Информа-
ция, необходимая для объединения в группу нескольких
сегментов, содержится в директиве GROUP, имеющей сле-
дующий синтаксис:
(имя группы) GROUP (имя сегмента)[,(имя сегмента)]
Параметр (имя группы) должен быть уникальным
допустимым именем, которое задается программистом
или транслятором с языка высокого уровня. Имена сег-
ментов относятся к тем логическим сегментам, которые
объединяются в группу.
Директива ASSUME сообщает ассемблеру, что доступ
к символам в сегменте или группе можно реализовать с
помощью данного регистра. Встретив переменную, ассемб-
лер автоматически транслирует обращение к ней с учетом
соответствующего префикса замены сегмента, если он не-
обходим. Следует особо подчеркнуть, что ASSUME только
сообщает ассемблеру о соответствии сегментов сегмент-
ным регистрам, а не производит их установку (это преро-
гатива и одновременно обязанность программиста) и про-
веряет, действительно ли встретившийся в программе сим-
вол находится в одном из сегментов, имена которых встре-
чались в ASSUME.
Для ясности и удобства документирования большие
логические сегменты в программе следует разделить, если
это возможно, на несколько менее крупных процедур.
Процедура должна содержать ту часть кодов сегмента,
которая используется для независимых или специальных
функций. В виде процедуры можно оформить любой фраг-
мент любого сегмента, однако чаще всего так описывается
последовательность кодов, которая неоднократно вызы-
вается по команде CALL. Директивы ассемблера PROC и
ENDP предназначены для указания начала и конца про-
цедуры. Вместе с директивой PROC могут быть заданы
параметры NEAR и FAR, которые позволяют ассемблеру
следить за тем, является ли процедура внутрисегментной
или межсегментной.
8.4. СИСТЕМА ПРОГРАММИРОВАНИЯ MASM
8.4.1. Процесс ассемблирования
Поясним структуру программы, рассмотрев процесс
ассемблирования. Как видно из рис. 8.3, входом для
ассемблера является исходный модуль (по умолчанию,
«ЙИЛ ЛИСТИНГА
(«. LST.СОН.РЯН1
06'ВКТНЫИ модуль
( и.OBJ )
Рис. 8.3. Вход и выход ассемблера
ФАЙЛ
ПЕРЕКРЕСТНЫХ
ССЫЛОК («.САР)
должен иметь расширение ASM), подготовленный любым
редактором текста. Выходом являются объектный модуль
(OBJ), листинг (LST) и файл перекрестных ссылок (CRF).
На рис. 8.4 показана упрощенная внутренняя струк-
тура двухпроходного ассемблера. Цель первого прохода —
Рис. 8.4. Двухпроходной ассемблер
279
получение информации о местоположении идентификато-
ров, второго — генерирование машинного кода. Для лока-
лизации идентификаторов в ассемблере предусмотрена
переменная, называемая счетчиком ячеек (адресов). Ее
можно считать указателем, который в ходе ассемблиро-
вания динамически фиксирует относительные позиции
(т. е. смещения) внутри каждого сегмента. Таким образом,
при сканировании программы производится инкремент
счетчика ячеек на число байтов, занимаемых операторами,
и при переходе из одного сегмента в другой счетчик ячеек
сбрасывается в нуль. В ассемблере MASM именем, кото-
рое позволяет программисту непосредственно обращаться
к счетчику ячеек, является символ $.
На первом проходе ассемблер с помощью счетчика
ячеек строит таблицу идентификаторов. Элемент этой таб-
лицы содержит тип и имя сегмента, в котором определяет-
ся соответствующий идентификатор, а также тип и имя са-
мого идентификатора. На втором проходе эта информация
используется при генерировании команд, операнды кото-
рых содержат идентификаторы. Ассемблер имеет две таб-
лицы — машинных команд и директив, в которых нахо-
дятся мнемоника, коды операций и т. п.
Рассмотрим функции первого и второго проходов
ассемблера. Когда при первом проходе в самом левом поле
оператора встречается метка или переменная, говорят,
что она определяется. В этот момент метка или перемен-
ная связывается со смещением, для чего в таблицу имен
помещается текущее содержимое счетчика ячеек, символи-
ческое представление метки или переменной и другие ее
атрибуты. При достижении директивы END первый про-
ход заканчивается и начинается второй. Кроме ассембли-
рования машинных команд, при втором проходе вводятся
константы инициализации из директив определения дан-
ных и вычисляются выражения, содержащиеся в операн-
дах команд и директив. Когда при втором проходе встре-
чается директива END, выходные файлы ассемблера вы-
водятся на соответствующие периферийные устройства, и
процесс ассемблирования заканчивается.
Если в момент появления в операнде переменной или
метки она уже определена, имеет место обращение назад;
в противном случае — вперед. Поскольку длина команды
зависит от атрибутов операндов, которые могут быть не
указаны явно, при обращении вперед ассемблеру при-
ходится предполагать, на какое значение выполнить инкре-
мент счетчика ячеек. Неправильное предположение либо
280
вызовет ошибку ассемблирования, либо заставит второй
проход компенсировать ошибки с получением неоптималь-
ного кода. Желательно явное указание атрибутов с по-
мощью соответствующих операторов и префиксов замены
сегмента, например SHORT, PTR, ES: и др.
Рассмотрим команду JMP EXIT. Если EXIT является
обращением вперед, в момент появления команды ассемб-
лер не знает тип перехода: короткий, близкий или дале-
кий — и поэтому резервирует для команды 3 байта (по
умолчанию, все метки близкие). С другой стороны, коман-
да JMP FAR PTR EXIT, без сомнения, имеет длину 5 байт.
Аналогичная ситуация имеет место в команде MOV АХ
OPERAND, где OPERAND является обращением вперед к
сегменту, отличающемуся от сегмента DS (например, SS).
При первом проходе ассемблер предполагает, что должен
использоваться сегментный регистр DS, и не учитывает
необходимого префикса замены сегмента. Это вызовет
ошибку при втором проходе.
Исходя из указанных особенностей, можно сделать
следующие выводы:
1) необходимо применять атрибутные операторы для
явного определения типов операндов во всех коман-
дах JMP;
2) следует помещать все директивы определения
данных перед командами (т. е. сегменты данных перед
сегментами кода);
3) если выражение в операторе EQU обращается к
имени переменной или метки (или к имени, определен-
ному в другом операторе EQU), оно должно быть направ-
лено назад;
4) поскольку ассемблер просматривает исходный текст
только до директивы END, допускается хранить неисполь-
зуемые фрагменты текста программы после END.
8.4.2. Исходный модуль программы
Входом для ассемблера является файл, содержащий
исходный текст программы. Более полную информацию
несет ее листинг, однако он всегда на 41 позицию шире
исходного текста, что необходимо учитывать при докумен-
тировании программы. Макроассемблер MASM имеет
группу директив управления листингом и форматом,
позволяющих программисту производить постраничную
разбивку текста, управлять заголовками страниц и подав-
лять печать всего объектного файла или его частей. Так,
281
для управления страницами листинга используется дирек-
тива РАСЕ [(длина)] [.(ширина)], где значением пара-
метра (длина), если он указан, является длина новой стра-
ницы в диапазоне от 10 до 255 строк (по умолчанию, 50).
Значение второго параметра — это ширина новой стра-
ницы в диапазоне от 60 до 132 символов (по умолчанию,
80). Если директива задана без аргументов или с необя-
зательным аргументом [ + ], ассемблер начинает новую
страницу.
Е1риведем исходный текст программы вывода на дис-
плей слова МРТИ. Директива PAGE 60, 80 устанавливает
формат листинга 60 строк по 80 символов в строке на
страницу. NAME First____program определяет имя модуля,
которое затем передается компоновщику. Директива
TITLE. Первая программа определяет заголовок для
каждой страницы листинга. Так как программа исполь-
зует операции MS-DOS, она должна резервировать стек
размером не менее 128 слов, причем тип STACK указывает
на объединение стека программы с системным стеком.
В сегменте data содержится сообщение ’МРТИ’, завер-
шающееся ограничителем ’$’ (для вывода строки будет
использована функция 9 прерывания INT 33). Программа
будет запущена загрузчиком операционной системы с мет-
ки start в сегменте code (так как указано END start) и
начнет свою работу с того, что установит регистры SS,
SP и DS на стек и данные соответственно. Программа
завершается обращением к функции 4ch MS-DOS, по
которой управление будет передано в вызывающую про-
грамму:
PAGE 60,88 Дананг 60 нроа
;по 80 сааволов
НАНЕ Firstjrograii ;Иия иоша Ш
;кожпоновжака
TITLE Вемаа програт Заголовок ли
;штша
stack SEGMENT STACK ,Речернарованае стека
В! 2&3 В8Р (!) 256 слов >;а.
top LABEL 808В ;вьзтв HS-DOS,
stack ESDS jtC'P-sepiHHa стека
data SEGHEH"
less DS .заканчивать
data EAL'S рграттлем $
code SEGMENT ,3aгрузчик DOS
ASSuKE cs'code [установит cs на ;сегмент code
start: ;Точка входа ;в дрогранму
cli [Установка ss и
eov ax,stack ;5р на сегмент
bov ss.ax [стека и вернину
282
BSV sp,OFFSET
sti
ASSB8E ss1stack
BOV ax, data
bov ds.ax
ASSOHE ds:data
lea di.eess
bov ah,9
int 21h
bov ah,4ch
int 21h
code EHDS
Ш' start
Bacns'i данная и уха
top ;ciesa cootner-
;cibshho
;Уставовка cer-
'.мента данный
;n сообщение об
;згой ассемблеру
;В dx смеменяе
;строки
;3авер®ение лро-
;Грайна
;Ковец сегиента кода
;Конец обрабаты-
ве точки входа
8.4.3. Запуск макроассемблера MASM
и формат листинга
После создания исходного файла можно вызывать
макроассемблер MASM, который предназначен для преоб-
разования исходной программы в перемещаемый объект-
ный файл. Впоследствии он может быть связан с другими
файлами программой LINK, в результате чего образует-
ся единый выполняемый модуль. Кроме того, макроас-
семблер может создавать файл листинга и файл перекрест-
ных ссылок (с расширениями по умолчанию LST и CRF
соответственно).
Существуют два способа вызова транслятора. В первом
случае необходимо ввести MASM. Макроассемблер за-
гружается в память, после чего последовательно выдают-
ся четыре подсказки, на которые требуется ответить. В кон-
це каждой строки можно указать один или более ключей.
Подсказки приводятся в табл. 8.24 (в квадратных скоб-
ках заданы значения, принятые по умолчанию).
Чтобы вызвать транслятор вторым способом, необхо-
димо ввести следующую команду:
MASM (исх. ф.), (объ. ф.), (листинг) ,(перекр. ссылки) [/(ключи)]
Элементы этой команды являются ответами на четыре под-
сказки ассемблера. Ключи (табл. 8.25) управляют выбо-
ром тех или иных функций при работе транслятора и вво-
дятся в конце строки ответа.
Существуют также два символа, обеспечивающих вы-
полнение некоторых функций при вводе команд вызова
транслятора. Символ точка с запятой (;), за которым
следует возврат каретки, может быть задан в любой мо-
мент при ответе на подсказки, но только после ответа на
вопрос об имени исходного файла (первая подсказка).
283
Подсказка
Ответ
Таблица 8.24
Source filename
[.ASM] :
Object filename
[source. OBJ]:
Source listing
[NUL. LST]:
Cross reference
[NUL. CRF]:
Ввести имя ассемблируемого файла. Имя
файла ввести обязательно (умолчание не до-
пускается); расширение по умолчанию — ASM;
в противном случае указать расширение в явном
виде
Ввести имя объектного файла. По умолчанию,
оно совпадает с именем исходного файла; рас-
ширение по умолчанию — OBJ. Чтобы было при-
нято значение имени и расширения по умолча-
нию, следует вместо ответа на подсказку ввести
только символ возврата каретки
Ввести имя файла листинга; ио умолчанию,
листинг не выводится. Если ввести имя без
расширения, ио умолчанию, принимается LST
Ввести имя файла перекрестных ссылок; ио
умолчанию, файл перекрестных ссылок не со-
здается. Если ввести имя без расширения, то,
по умолчанию, CRF
Таблица 8.25
Ключ Выполняемая функция
/D Указывает, что будет выдан листинг обеих фаз ассембли-
рования. Сравнение этих листингов позволяет обнаружить
ошибки фазы. Ключ не оказывает никакого действия, если
имя файла листинга не указано (листинг не создается)
/О Вывод листинга производится в восьмеричной системе
(коды и смещения выводятся в восьмеричной системе)
/X Подавляет вывод в файл листинга блоков исходного текста
в том случае, если выражение, заданное как условие ассембли-
рования, ложно
/МХ Переводит ассемблер в режим распознавания верхнего
и нижнего регистров
При его вводе на все остальные подсказки принимаются
ответы по умолчанию. Этот символ нельзя использовать
для отказа от ответа на отдельную подсказку (для этого
используется возврат каретки).
Предположим, что исходный текст программы с: prog-
ram.asm и masm.exe находится на диске С. Тогда трансля-
цию программы можно выполнить следующим образом:
С>MASM PROGRAM,.PROGRAM,PROGRAM<ВВОД)
В таком случае на диске С появятся три новых файла:
program.obj, program.1st, program.erf. При возникновении
ошибок в процессе трансляции ассемблер выдает соответ-
ствующие сообщения на экран и фиксирует их в выходном
284
листинге program.1st (файлы program.obj и program.erf
не создаются).
Листинг, выдаваемый ассемблером, делится на две
части. В первой из них содержатся: номер для каждой
строки исходного текста (в том случае, если создается
файл перекрестных ссылок); смещение для каждой исход-
ной строки, генерирующей код; генерируемый код; знак
плюс (+), если код возник в процессе макрогенерации,
или символ С, если код возник в результате ассембли-
рования файла, включенного по INCLUDE; исходный опе-
ратор. Вторая часть листинга включает: макросы — имя
и длину в байтах; структуры и записи — имя, ширину
поля; сегменты и группы — имя, размер, тип выравнива-
ния, тип связывания и имя класса; символы — имя, тип,
значение, атрибуты; количество предупреждающих сооб-
щений и ошибок. В листинге используются следующие
обозначения: R — компоновщик перемещает значение,
расположенное слева от R; Е — внешний символ; = — в
операторе задана директива EQU или =; пп/ — оператор
с префиксом REP или LOCK; [х] — выражение в DUP;
хх— значение в скобках, следующее за DUP, и т. п.
8.4.4. Программа перекрестных ссылок CREF
Программа перекрестных ссылок предназначена для
оказания помощи пользователю на этапе отладки про-
грамм. Она выводит упорядоченный список имен в спе-
циальный файл, создаваемый ассемблером. С помощью
листинга можно легко определить положение любого име-
ни по номеру строки.
Прежде всего необходимо получить файл перекрест-
ных ссылок. Затем программа пепекрестных ссылок преоб-
разует его в упорядоченный по алфавиту список имен.
Полученный в результате файл, по умолчанию, имеет рас-
ширение REF. Для каждого имени в списке указываются
номера строк, где имя встречается в исходной программе.
Имена перечислены в возрастающем порядке. Номер
строки, в которой имя определено, указывается симво-
лом .
8.4.5. Компоновщик LINK
Компоновщик предназначен для объединения отдельно
оттранслированных объектных модулей в один переме-
щаемый загрузочный модуль с присоединением библио-
течных процедур
285
Программа LINK может вызываться несколькими спо-
собами. При одном из них требуется ввести LINK- Про-
грамма загружается в память, после чего последовательно
выдаются четыре подсказки, на которые нужно ответить.
В конце каждой строки можно указать один или более клю-
чей. Подсказки приводятся в табл. 8.26, а ключи — в
табл. 8.27.
Таблица 8.26
Подсказка Ответ
Object Ввести список объектных модулей, отделяемых
modules [.OBJ] EXE file [.EXE] MAP fi le [Nul.MAP] Libraries [.LIB] друг от друга пробелами или знаками плюс ( ) Расширение по умолчанию — OBJ; в про- тивном случае указать в явном виде По умолчанию, принимается имя первого в списке объектных модулей с расширением EXE. Другое расширение недопустимо Листинг, по умолчанию, не создается, тре- буется указать имя. Расширение по умолча- нию — МАР Ввести имена библиотек, в которых должен осуществляться поиск; имена отделяются про- белами или знаками плюс (+). Расширение по умолчанию— LIB
Таблица 8.27
Ключ Выполняемая функция
/HIGH /MAP /STACK.’.<Ч11сло> Выполняемый файл должен располагаться в памяти по старшим адресам; по умолчанию, он расположен по младшим адресам Должны выводиться все глобальные символы определенные во входных модулях; по умолча- нию, выводятся только ошибки Определяет размер стека; по умолчанию, он вычисляется автоматически
Обработаем программой LINK имеющийся, объектный
модуль program.obj.
Загрузив полученный выполняемый файл (он всегда
будет иметь расширение EXE), получим на дисплее сооб-
щение :МРТИ.
В заключение предлагаем рассмотреть и самостоятельно протранс-
лировать следующую программу:
stack ЗКВВП STACK
И 128 ВОР (!)
stack EOS
data SSGMBH
286
Var M 1234h
Mess» 80 ' - ciobo',10,13,
HessBL DB ' - младахй байт',10,13,
MessBB DB ' - стараий байт',10,13,T
data EHDS
code SXGKMT
ASSUME cs:code,ss-.stack
RecCallO PHOC HEAR ;
posh ат ; Вазов BecCalll
>ov al,ah ; преобразования и
call BecCalll; вввода стариего,
pop ax ; затем ададиего байта
; Процедура BecCalll преобразует байт в ;
; AL в две иестнадцатеричиые цифра в ;
; выводит hi ;
BecCalll PROC HEAR
push ax
shr al, 1
shr al,l
shr al, 1
shr al, 1
call RecCall2
pop ai
and al,0fh
; йроцедура RecCall2 преобразует мдад- ;
; ayt тетраду Al ( стармаи равна 0 ) в ;
; код аестиадцатеричнон цифра и выводит ;
; ее ;
RecCall2 PROC HEAR ;
Содержимое AL
add al,90h
daa
adc al,40h
daa
push dx
«ov dl.al
aov ah,2
iut 21h
x=0-9 ! :
09х !
09s !
Odx !
030-039!
' О'-V!
Вывод
симвода
x-a-f
09xh
Oaxh (x-1-6)
flesh
041-046
'А'-'Г
на
днспдей
pop dx
ret ; ! ВОЗВРАТ ИЗ ВСЕХ !
RecCall2 E8DP
BecCalll E8DP
RecCallO ENDP
; процедура вывода строки на дисплей
displ PROC NEAR
«ov ah,9 ; вывод через
1st 21h ; Функцию 9
ret
displ END?
start:
«ov ax,data ; установка сегнента
aov ds,ax ; данния
ASSUME ds:data
lea bx,Var ; получение адреса Var,
aov ax, [bx] ; чтение сюва но адресу
287
call RecCallQ
lea dx,Ness>
call displ
bov al,[bxI
call RecCalll
lea dx.MessBL
call displ
aov al,[bxvl]
call RecCalll
lea dXgMessBH
call displ
nov ah,4ch
int 2 lb
code ENDS
Ш start
; » вывод его на днсяхей
; вывод
, сообщения
; чтение идадвего байга
, вывод его на Лидией
, вывод сообдеии!
; чтение стараего байта
; вывод на дисплей
; вывод сообденин
; выход
Результаты ее работы представлены ниже:
1234 - слово
34 - идадаий байт
12 - стара»» байт
Этот пример демонстрирует одну из особенностей архитектуры
микропроцессоров Intel 8086, которая легко запоминается с помощью про-
стого мнемонического правила «младшее по младшему адресу», т. е.
младший байт слова считывается по четному адресу.
8.5. ОБЪЕДИНЕНИЕ ОБЪЕКТНЫХ МОДУЛЕЙ
Рассмотрим построение программ, состоящих из не-
скольких раздельно протранслированных объектных моду-
лей, которые должны быть соединены компоновщиком в
единый загрузочный модуль. Можно выделить два уровня
связи между модулями: по данным и по управлению. Связь
по управлению включает совокупность способов вызова
модулей, условий их инициализации и завершения. Инфор-
мация, передаваемая между модулями, и наличие совмест-
но используемых областей памяти приводят к понятию
сопряжения (связи) модулей по данным. По аналогии с
языками высокого уровня в ассемблере различают локаль-
ные и глобальные объекты. С каждым модулем связаны
два списка идентификаторов: внешних, т. е. тех, которые
объявлены в другой программе, но используются в этом
модуле, и глобальных.
Для работы с этими списками программист использует
директивы EXTRN и PUBLIC, имеющие следующий син-
таксис:
EXTRN (идентификатор):(тип) [,...]
где (индентификатор) представляет собой имя, определен-
ное в другом модуле, а (тип) должен быть обязательно
288
допустимым для (идентификатора) и может принимать
следующие значения: 1) BYTE, WORD, DWORD—для
переменных; 2) NEAR, FAR — для меток и имен процедур;
3) ABS — для констант. Директива EXTRN должна
использоваться только в том сегменте, в котором опреде-
лен этот внешний идентификатор, поскольку в противном
случае компоновщик может не разрешить эту ссылку;
PUBLIC (идентификатор)
где параметр (идентификатор) является константой, пе-
ременной, меткой или именем процедуры, определенной
в этом модуле.
В качестве примера рассмотрим программу вывода содержимого
файла на стандартное устройство stdout. При обращении к некоторым
функциям MS-DOS возвращается код ошибки в регистре АХ при
установленном признаке переноса CF. Для распознавания этого кода
ошибки и вывода сообщения на консоль (файл stderr) полезно разра-
ботать процедуру обработки ошибок и компоновать ее со всеми про-
граммами, интенсивно работающими с ОС. При рассмотрении исход-
ного модуля error.asm следует обратить внимание на реализацию до-
ступа к строкам переменной длины с помощью таблицы, содержащей
для каждого кода ошибки смещение начала строки в сегменте кода и
ее длину. Текст программы приведен ниже:
NAME error
мх_еггог Е81! 19
bell SQL1 1
err . SEGMENT CODS'
AS3GNE cs: err, dr. err
PUBLIC error
error PROC FAR
jo start
ret
start:
pash ds
pash ax
рази bx
pash ox
pash dx
, Чнсю идентнфнынруеиых оанбок
: Звуковой сигнал
: Если СУЯ, ю овнбка,
; s противном случае - выход
: Сохранение DS
: Сохранение
; рабочих итастрс'8
свр ах.вах.еггог , Если отёка известна,
jbe prod , то прцишь,
bov ax.tax.error ; am синька неизвестна
prod
lea bx,table_addr ; В ВХ адрес строки,
shl а?.,1 ; соответствуюциа коду овнбки
shl ах,1
add Ьх.ьх
вот ах.err
вот ds.ax ; в DX адрес
bov dx,[bx] . буфера
bov и,ЕЬхт2] . 8 И длина сообщения
bov Ьх,2 запись в
aov ah,40h . фш
10 Скляров В. А.
289
int 21b ; stderr
l&v dl.bell ; подача
B6V ah, 2 ; звукового
int 21h ; сягнада
SOV ah,3 ; Реакции на о|ибку; нахать любую
hit 33 ; шшу вли снять no Ctrl-Bre&k
pop pop dx ex ; восстановление
pop bx ; рабочих
pop ax ; регястров
pop ds StC ret error ШР tablejiddr LABEL HEAR № errO,eri‘-еггй Dtf errl,errZ*errl DH e?>2.errS-errD DH err3,erH-err3 DH errterr5*err4 DH err5,err6-err5 DH eirS,err?-err6 DH errl,errS-err? DH errB,errS-err8 DH err9,enl0-err9 DH errlO,errl1-errlD ; и DS
D'iI errll,errl2-errll
88 errl2,errl3-errl2
JU errl3,errU-errl3
И errld,errl5-errl4
И errl5,errl6-errlb
88 errl6,errl?-errl6
88 errl?,errl8-»rrl?
88 егг13,еггвах-егг18
88 errm.eiiderr-erriax
errO db 10,13,
errl db 10,13,'ЗНТЗЗ?-Недопустниый номер операций
err2 db 10,13,'ШЗЗ’-Wj не найден
еггЗ db 10,13,' ШТЗЗ?-Катак>г не найден
errl db 10,13,' 111337-Onjseo сушкой иного файлов
егг5 db 10.13, "IHT33?-Неправнjuice обраденне
еггб db 10,13,'1НТЗЗ?-Венравндьный нонер файда
errl db 10,13, ’ 18ТЗЗ’-0аруиен бш управления наняты!
err! db 10,13,’I8T33?-8aio наше 0;
еггЭ db 10,13,'Ш33?-Веправнлнай адрес блока памяти
errlO db 10,13,'ШЗЗ’-Ееправишая среда
errll db 10,13, ЧЯТЗЗ’-ВеправвЛний фориат
errl2 db 10,13,' 18ТЗ31 -Яедопустинмй код доступа
егг13 db 10,13,'тТЗЗ’-Педопустиине данные
errll db 10,13,
errll' db 10,13,ШТЗЗ?-0едопустнный номер устройства
errlS db 10,13,' ГВТЗЗ’-Пояятка умигивгь saraior
errl? db 10,13,'1НТЗЗ?-Долдно быть то де устройство
егг18 db 10,13,' 1НТ332-С1ИВКОМ много файдов
еггвах db 10,13,'Неизвестная снимка
eaderr label byte
err ENDS
888
290
Головной модуль программы получает имя файла для вывода из
командной строки и использует для обмена с диском 128-байтную
область DTA в префиксе программного сегмента (см. гл. 3). Другими
словами, мы описываем уже созданный сегмент и директивой ASSUME
DS:PSP связываем его с регистром DS только для того, чтобы установить
идентификатор DTA на требуемую область памяти. Поскольку любая
программа может иметь только одну точку входа, все модули, кроме
головного, должны заканчиваться директивой END:
stack segjent para stack
d« 128 dap (?)
stackjop label nord
stack ends
psp segnent
org D8Dh
dta db 128 dup (?)
psp ends
code segaent
assuae cs:code
assuae ss:stack
assume ds:psp
assume es:psp
extra error:far
start:
aov ax,stack ; Установка
aov ss.ax ; стега
aov sp,offset stackjop ;
lea di,dta , конвертирование командной
ror bh.bh ; строки к Формату ASCIIZ (т.е. t
aov bl,[di] ; строке, оканчнвамдейсв мавнн-
aov [bxrdirlj.byte ptr 0 ; нам ну геи — 00000000)
add di,2 ; открытие
bov dx.di sov al.O bov ah,3db int 33 call error jc endpr iov bx.&x bov ex,128 lea dx.dta loopO; bov ah,3fh int 33 call error csp ax,0 je exit push bx push ex bov cx.ax bov hx,l bov ah,40h int 21h pop ex pop bx jbp loopO exit: bov ah,3eh ; файда ; ди ; чтении : в Bl номер файн ; дднна буфера ; снедение буфера ; чтение блока ; нз файда ; etJH крочнтаио 0 байт, ; то внод ; сохранение номера Файда ; н ддина буфера ; в CI чяедо жрочитанныд ; байтов, в ВХ номер stdout ; вмдод в Фай а ; восстававшие параметров ; чтении ; закрытие
291
ht 33
endpr
bov ah.Olch
int 33
code ends
; файла
; вйход
end start
8Л МАКРОКОМАНДЫ
Макрокоманды дают возможность создавать блоки
текста программы, которые затем подставляются в нужное
место по имени блока, причем допускается параметри-
ческая настройка каждого вызова. Это очень мощный ме-
ханизм обработки текста программы, позволяющий созда-
вать собственные команды для программирования на
ассемблере. При появлении в тексте программы директивы
вида
(имя_макро) MACRO [(фикт парам.),...]
ассемблер не транслирует текст программы в машинные
коды до тех пор, пока не встретится директива ENDM,
Этот блок операторов между директивами MACRO и ENDM
составляет тело макрокоманды, или макроопределение.
После того как макрокоманда определена, (имя____макро)
используется для ее вызова, и при каждом его появлении
ассемблер берет текст из макроопределения и подставляет
его в транслируемый участок программы. Обычно при
обращении к макрокоманде указывается строка вида
(имя_макро) [(параметр),...]
Дело в том, что при макроопределении может указываться
список фиктивных параметров, каждый из которых лишь
резервирует место в строке. Фактические параметры рас-
сматриваются как список разделенных запятыми объектов,
которые подставляются на место соответствующего фик-
тивного параметра. Недостающие фактические параметры
заменяются символьными строками нулевой длины, а лиш-
ние игнорируются. Параметр, помещенный в угловые
скобки, воспринимается как единый литерал.
Несколько специальных символов имеют в макроко-
мандах особый смысл. Амперсанд & вызывает конкате-
нацию (сцепление) строк и применяется в тех случаях,
когда фиктивный параметр является подстрокой или за-
ключен в кавычки. Угловые скобки учитывают, что текст
между ними рассматривается как единый литерал, а повто-
292
ряющийся дважды символ точка с запятой (;;) запрещает
выдачу комментариев в макрорасширениях. Другая про-
блема связана с использованием меток в макрокомандах,
поскольку при повторном вызове макрокоманды метка
будет переопределяться. Директива LOCAL позволяет
объявить метку локальной в макрокоманде и при каждом
макрорасширении заставляет ассемблер генерировать
уникальное имя вида ??0000, ??0001 и т. д.
Макроассемблер имеет также специальный вид макро-
команд для реализации повторений различных фрагментов
программы. Эти макрокоманды повторения открываются
директивами REPT, IRP, IRPC и также должны заканчи-
ваться словом ENDM. Макрокоманда REPT (выражение)
повторяет указанное в (выражении) число раз тело макро-
команды. Макрокоманда IRP (фиктивный параметр),
(список параметров) подставляет при каждом повторении
следующий элемент списка параметров до тех пор, пока он
не исчерпается. Если же вместо списка параметров мы
хотим задать строку символов, необходимо применить
макрокоманду IRPC (фиктивный параметр), (строка сим-
волов) .
Макрокоманды позволяют генерировать код програм-
мы в зависимости от различных условий в момент трансля-
ции. Этот процесс называется условной трансляцией и вво-
дится с помощью директив вида
IFXXX аргумент
ELSE
ENDIF
где IFXXX определяет условие (см. табл. 8,28), при зна-
чении которого «истина» транслируется блок кода от
Таблица 8.28
Операция IF Условие трансляции
IF Выражение IFE Выражение IFDEF Имя LENDEF Имя IFB <параметр> IFNB <параметр> IFIDN <стр1>, <стр2> IFDIF <стр1>, <стр2> IF1 IF2 Выражение не равно 0 Выражение равно 0 Имя объявлено как внешнее Имя не было объявлено внешним Параметр равен пробелу Параметр не равен пробелу Строки <стр1> и <стр2> совпадают Строки <стр1> и <стр2> не совпа- дают Проход 1 ассемблера Проход 2 ассемблера
293
IFXXX до ELSE или ENDIF, если ELSE отсутствует.
При невыполнении условия транслируется блок между
ELSE и ENDIF, если он существует.
Директива INCLUDE осуществляет вставку в трансли-
руемую программу текста из другого файла и применяется
для подключения библиотек макрокоманд. Запись вида
IF1
INCLUDE (имя файла)
ENDIF
включает текст из файла только на первом проходе, когда
обрабатываются макрорасширения, и на втором проходе
в листинг текст уже не выводится. Обычно включаемые
файлы имеют расширение .INC. Ниже приводится текст
файла MY.INC, демонстрирующий некоторые аспекты
использования макрокоманд и применяемый в дальнейших
примерах:
он SQO О
off SW Offh
debug z on
; Байтовая табайца верекодкровки таблщи
; знакогенератора ALT в КМ.
AscCharzObOh
HEPT 48
DB AscChar
AscChar=AscChar+1
ШИ
DB 09Bh,QBCh,09Dh,0A5h,0A7h,Q83h,084h,Q85h
DB 086h,Q97h,095h,Q91h,092h,Q8Bh,a8Ch,0Alh
DB 0A3h,0A8h,0A6h,0A9h,0A4h,0AAh,08Dh,Q8Kh
DB 093h, 090h,Q98h,096h,099h,094h,09Ah,080h
DB 081h,082h,087h,088h,089h,08Ah,08Fh>09Sh
DB 09Fh,0A2h,OAOh,0ABh,0ACh,0ADh,0AKh,0AFh
A sc Cha rOeOh
МВТ 16
DB AscChar s,
AscChar AscCharal
SUDS
DB 0F0h,0Flh,020h,020h,020h,020h,0F6h,0F7h
AscCharz0f8h
REPT 8
DB AscChar
AscCharAscCharal
MOB
; Иакрококаада GetAndSetTect <аокер вектора) поучает указашй
; вектор, поиежает его в два сива паши с именем Oldlntmon.>h,
; а затеи рстааавдквает зтот вектор на ветку Int_(ao«.>h
; Папрниер, GetAndSetTect 9h будет работать, еси обработчик
294
; прериваник int 9h описан педдцмм образом:
, IntJh PROC FAB
; jap D»MD PTS cs.Oldlnt9h
; Oldlnt9h DS 2 DOP (?)
; iret
; Intjh EHDP
GetAndSetVect MACHO nuMvect
mov ax,35h»25SiAnusvect
int 21k
bov cs:OldInt4nuMvecti2,es
mov cs:OldlntSnunvect,bx
«ov ax,25h»256v4nuavect
lea dx, 1 nt .Anutvect
int 21h
ESDK
, Какрокошда Print предназначена ди вивода сообменнА
; Еориахьно разрешен вывод всех сообщений; бширопка вивода
; производится директивой debugroff
Print MACRO charjtring
DOCAD string,exitjrint
IFF debag - on
push ds
push cs
pop ds
lea dx,string
nov ah,9
int 21b
pop ds
jap exitjrint
string DB 'Acbar_string',10,13,'J'
exitjrint-
EDDIE
ENDM
Следует обратить внимание на директивы EQU и =.
Обе они присваивают идентификатору слева от директивы
значение выражения, стоящего в правой части. Однако
только директива = позволяет переопределить ранее
определенный идентификатор, что делает возможным
управление выводом отладочных сообщений с помощью
строк вида debug = on или debug = off.
8.7. ОБРАБОТКА ПРЕРЫВАНИЙ
Одним из важнейших применений ассемблера является
возможность написания на нем небольших резидентных
программ обслуживания периферийных устройств на
физическом уровне, называемых также обработчиками
прерываний. Традиционно эти программы принимают на
себя лишь часть функций по управлению устройством,
передавая управление на старый обработчик для реализа-
295
ции полного набора функций. Таким образом можно прий-
ти к представлению о цепочке обработчиков, последова-
тельно загруженных в память и передающих управление
друг другу до тех пор, пока не будет достигнут стандарт-
ный модуль MS-DOS или BIOS. Типичной является ситуа-
ция, когда несколько резидентных программ (знакогене-
ратор, калькулятор, антивирус), обрабатывающих аппа-
ратное прерывание от клавиатуры с целью обнаружить
«свою» комбинацию клавиш, вызывают друг друга в по-
рядке, обратном порядку их загрузки.
Можно выделить три возможности установки обработ-
чика прерываний: 1) полная замена обработчика; 2) вы-
полнение своих действий и затем передача управления
на старый вектор (предобработка, обычно связанная с
модификацией или фильтрацией параметров вызова);
3) вызов старого вектора и затем выполнение своего
фрагмента кода (постобработка, или модификация резуль-
татов) .
Первый случай не требует дополнительных поясне-
ний. Во втором случае обычно применяется следующее
решение:
IKTJANBBSR РЯОС m
; обработчик пошовиен
J8P ВМВ РТН CS.-OWJNLOFFS
OLDJHTJFFS В» 1
0LDJKTJ8G В» 1
IHTЛШШ ИВР
Обратите особое внимание на содержание баланса стека,
так как команда IRET будет выполнена только в послед-
нем обработчике. В третьем случае старый обработчик
прерывания будет вызываться командой межсегментного
вызова процедуры, сохраняющей в стеке только сегмент
и смещение адреса возврата, а выход происходит по ко-
манде IRET, восстанавливающей дополнительно регистр
признаков. Исходя из этого, обычно перед вызовом заносят
в стек регистр признаков командой PUSHF. Постобработ-
чик имеет вид
IKIJUTOLffl РЯОС FAE
P0S8F
C4LL BFORB PTR CS:OLB_1HT_OFFS
; обработчик пользователи
№ ; или ИТ 2, еея модифицируется признаки
OLBJHTJ)FFS В» 1
olb_iht_seg в» ’
1STJASBBS» №
296
Заметим, что для каждого обработчика необходима
инициализирующая часть, в минимальном варианте вы-
полняющая следующие действия: 1) получение установ-
ленного вектора прерываний и сохранение его в ячейках
OLD_INT_OFFS, OLD_INT_SEG; 2) установка век-
тора прерываний на INT____HANDLER; 3) завершение
программы и сохранение обработчика резидентным в па-
мяти.
Приведенная ниже программа знакогенератора для
печати представляет собой типичную программу обслужи-
вания с предобработкой. Получаемый в регистре AL байт
перекодируется этой программой в воспринимаемый печа-
тающим устройством код и передается стандартному
обработчику:
TITLE Printer FI-800 handler
cgroup GROUP ores,cinit ; 2 сегмента
SEGMENT
объединены в группу
Сегмент сгез содержит
резидентном часть программы
; Описание габиц» перекодмроькк
IlatTabl LA8SL BYTE ; как байтовой в подклечение ее
IHCLODE MY.IMC ; из файда A.:MY.IHC
ASSOHS cs:cgroup,ss:stack
IntJVh PROC FAR
and ah,ah
jnz OldVect
cap a1,80b
jb OldVect
push ba
Если вывод на печать
ко* белые 128
то ...
lea bx,IlatTabl
sub al,80h
Klat cs:XlatTabl
pop bs
перекодировка
байта
в регистре
Ab по табхнце
перекодировки IlatTabl
OldVect.
jap DWORD PTR cs;01dInt!7h
OldlntlTh 0» 2 OOP (2)
IntJVh ENDP
cres ENDS
; Сегмент инициализации cinit
cinit SEQUENT
Hain PROC FAR
push ds ; сохранение пазатеи на PSP
Push cs ; Установка
pop ds ; обработчика
GetAndSetVect ITh ; ирернваний
Print ( Фильтр дли вереходироваим >
Print (таблицы ALT в Ш при выводе на печать)
Print ( тстаиовлен >
pop dx ; Получение в DX
sub dx,cinit ; размера резидентной части
neg dx ; програиин в параграфах
aov ax,31Q0h ; Завериенне программы в
int 21h ; сохранение ее резидентной
297
Bain EHDP
clnit ENDS
EHD Main
Следующая программа обрабатывает прерывание INT
9 и INT 16Н с целью модификации поступающих с кла-
виатуры кодов (из нижнего регистра в верхний), причем
режим модификации переключается в триггерном режиме
комбинацией клавиш ДОП — ВВОД (Alt — Enter):
TITLE KEYBOARD HAHDLEH I FOR EXAMPLE i
RobBios SEGMENT At OFOQQh
ORG OFFFEb
HachineJD DB 1
RooBios ENDS
cseg SHOW ores,cinit
ores SEGMENT
ASSUME cs:cseg INCLUDE MY.INC ; Таблица перекодировки будет
Intjh F8K FAR sti pash az : линией ; Сохранение рабочих регистров
pash es ; в стеке
bov H,Wh ; X установка ES=49h
SOY in es.ax al ,6»h ; Чтение екэи-кода и сравнение
al,Ich ; с «мои ‘ENTER’
jiie Hojnter
test byte ptr es:[llh],8 ; Определение no байту гостов'
jne Ait_andjnter ; ина, иахата in хдавпа ALT'
Hojnter: сП pop es ; Если сцепление клавнн не
POP ax : обнаруиено, to переход х
DB Oeah ; стандартному обработчику Маленький трюк '.!!
OldintSli DH 2 MP (?) ; ОЕАЭ есть ход коианди JMP TAB
Delay ЙЙ 2uuGa ; ди режима межсегнентной прямой адресации Вреив звучании
AlLandJnter
push BOV ex ex,csiDelay ; сх - времв звучания,
aov ah,4 ; ah • частота
xor ; ди Tlaj’-O BYTE PTR cs.‘Flag,-Offh ; Инвертирование Flag
js Sound ; и если 0,
ahi ex, 1 ; то увеличение
shl ex, 1 ; на 8 длительности
shl ex, 1 ; сигнала
BOY ah,5»h ; понижение частот!
Sound: in al,61h ; Разрежение генерации
or 81,3 ; звука от
out 6111,al ; таймера
SOY al,0B6h ; Управлвивее слово
298
out 43h,al ; тайнера (рехнм 3)
BOY al,» ; Хдадиин байт
out 42h,al ; коэффициента леденив
BOY al, ah ; Старанй бант
out 12h,al ; коэффициента деаеииз
TiseSonnd: Задержка на время
loop TiieSonnd звучаннв
in al,61h ; Запрет
and al.OFCh ; генерации
out 61h,al ; звука
pop CI
in al,61h Подтверждение
BOY ah,al ; приема ехэн-кода
or- al,80h ; контроллеру клавнатурн
ont 61b.nl
imp SHORT Belt lyForBeset ; Задерлка ди генерация
DelayForReset' ; единичного уровня сигнала
BOY al,ah ; за счет сброса внутренней
out 61b,al . ; очереди конанд КВ
cii
BOY &i,20h ; Конанда контролеру прервва-
ont 20h-al ; ннй Конец нрернваннв"
POP es ; Восстановление
pop ax ; регистров
iret ; и ьи’Од аз прерывания
Iat_9h ENDP
Flag DB Offh ; Признак Черекодвровка
; вкдччена/внкичена"
; Исходное соетовнне -
; ьншчено
Int_16h PROC FAB
СВР се:Flag,0 ; Ecjh Flag - “впечен'
Convert ; то преобразование,
jBpToOldBandler: ; иначе перевод
1др DWBD PT8 cs:01d!ntl6h ; no старой? веной
OldlntI6h DU 2 DDF (?)
Convert:
push!
c»p ah,2 ; Bcm функция ah<2,
jb GetKey ; то внзов no CALL
popf
j»p SHORT JapToOldBandler
GetKey.
call DSORD PTR cs:01d!ntl6h ; Вызов старого обработчика
pushf ; и сохранение признаков, так
sti ; как используется ZF
сдр al, a ; Если ASCII-код клавнин
jb CharlnGpperCase ; в регистре al наюдитсд
rap al. 's ; в диапазоне 'а'-'з',
ja ClarlnDpperCaae ; то сброс
and al,61611111b ; бита 5 и получение 'A’-'Z'
CharlnOpperCase:
Popf ; Во останов шне признака (2F)
'ret 2 ; и возвращение нз прернваннн
; с удалением старик прнзна-
; хоь из стека
Int_16h ENDP
ores SUDS
299
SUBTTL НАШ
PASS
cin it SEGMEHT
Hain РЯОС FA»
push ds
; Установка вектора прерываний
push cs
pop ds
ASSOHE ds:cseg
GetAndSetVect 9h
GetAndSetVect 16h
; Определение типа цапана jih установка длательноста сагнала
CPU80286 EQO Ofch
aov ax,RoaBios
sov es,ax
ASSBHS es'SonBios
>ov al, esMachiBe_ID
свр al,C?P802c6
Jne k'oHodifyDelay
sbl csDelay, 1
HoKodifyDelay:
; Вывод сообденая
Print Oarpyiena програиаа (ними прописных букв»
Print < Установка и снятые фильтра но Alt - Enter >
: Вычисление в dx размера резидентной часта программы в параграфа
pop ds
sub di.cinit
neg ds
: Заверит программу а оставать ее резадентной в памяти
sov ат 3100b
let 21h
Hain ЕЕ?
emit EKDS
Efiv Hain
Существует еще один способ установки обработчиков
прерываний, отличающийся тем, что старый вектор сохра-
няется в каком-либо свободном векторе прерываний. Этот
способ более нагляден, поскольку позволяет вызывать
старый обработчик непосредственно командой INT, однако
он не допускает повторной установки обработчика и не
защищает от других программ. Другими словами, любая
модификация этого вектора приводит к разрыву цепочки
обработчиков и непредсказуемому поведению машины.
8.8. ИНТЕРФЕЙС С ЯЗЫКАМИ ВЫСОКОГО УРОВНЯ
При разработке больших программных систем часто
возникает необходимость оптимизировать отдельные, наи-
более часто вызываемые процедуры на языке ассемблера.
Большинство трансляторов с языков высокого уровня
предоставляет две возможности: использование простей-
шего однострочного ассемблера (INLINE в ПАСКАЛе и
зоо
asm в СИ) и подключение процедур на уровне объектных
модулей. Здесь мы будем рассматривать именно вторую
возможность (первая описана в гл. 6).
Разработка таких процедур на языке ассемблера тре-
бует ясного представления о том, каким образом взаимо-
действуют процедуры и функции в разных языках. Об-
щим для большинства из них является то, что параметры
вызова передаются через стек с помощью такой последова-
тельности:
push para
push pari
call procedure
Однако на этом совпадения заканчиваются. По-разному
отрабатывается порядок загрузки параметров в стек (сле-
ва направо или справа налево), параметры передаются по
значению или по указателю (т. е. загружается в стек зна-
чение параметра или его адрес), удаление параметров из
стека может происходить либо в самой процедуре, либо
после команды CALL. Сравнение с этой точки зрения двух
популярных языков программирования приводится в
табл. 8.29.
Таблица 8.29
Критерий сравнения си ПАСКАЛЬ
Тип подпрограммы Функция Процедура/функ- ция
Направление передачи па- раметров Справа налево Слева направо
Параметры передаются По значению По значению и по указателю
Удаление параметров с по- мощью RET N ADD SP, N
Вследствие общности подхода рассмотрим только связь
программ на СИ и языке ассемблера, причем головной
модуль должен быть всегда написан на СИ, хотя в пре-
дельном случае он может быть пустым:
void extern cdecl assfunc (void);
main( ) {assfunc( ))
Следующий вопрос, который предстоит решить, связан
с типом ассемблерной процедуры и зависит от используе-
мой модели памяти. Для каждой из шести моделей памяти
(см. гл. 9) типы указателей на функции и данные сведены
в табл. 8.30.
30’
Таблица 8.30
Модель памяти Указат ель на функцию Указатель
па lauHbie
Минимальная (Tiny) near, CS near ds
Малая (Small) near, cs near ds
Компактная (Compact) far near ds
Средняя (Medium) near, cs far
Большая (Large) far far
Максимальная (Huge) far (ar
Макроассемблер МАСМ 5.1 поддерживает директиву
.MODEL имя_ модели, с помощью которой будет осущест-
вляться генерация атрибутов сегментов, совместимых с
указанной в ТУРБО СИ моделью памяти. Программист
должен только выбрать из табл. 8.30 необходимые типы
указателей и получить следующий текст:
.MODEL SHALL
.ж
PUBLIC _assfunc
jssfanc FBOC ИШ
ret
_assfunc EKDP
EHD
Директива .CODE для указанной в примере модели памяти
SMALL преобразуется в строки вида
_ТЕХТ SEGMENT BYTE PUBLIC ’CODE’
ASSUME CS:_TEXT
Появившийся перед именем функции символ подчеркива-
ния связан с особенностями компоновщика TLINK, при-
меняемого в составе ТУРБО систем фирмы Borland, кото-
рый добавляет его ко всем внешним именам. По этой при-
чине необходимо транслировать ассемблерную подпро-
грамму с ключом /МХ, переводящим ассемблер в режим
распознавания верхнего и нижнего регистров. Если функ-
ция имеет тип PASCAL, то все идентификаторы преоб-
разуются в верхний регистр и символ подчеркивания не
добавляется.
Рассмотрим подробнее последовательность передачи
параметров типа СИ и ПАСКАЛЬ. Если объявлен про-
тотип функции
void cdecl funcc(int pi, int p2, int p3);
параметры будут заноситься в стек справа налево (рЗ,
р2, pl) и затем будет сохраняться адрес возврата (слово
302
или двойное слово в зависимости от модели памяти). Число
параметров может быть помещено в стек, и после заверше-
ния работы функции они будут удалены. Этот механизм
позволил реализовать в языке СИ функции с переменным
числом параметров (va-функции).
Для функции типа ПАСКАЛЬ
void pascai funcpas (int pi, int p2, int p3);
параметры будут помещаться в стек слева направо (pl,
р2, рЗ) с последующим сохранением адреса возврата.
Функция при выходе сама удаляет параметры из стека с
помощью RET N.
Для доступа к параметрам в стеке используется свойст-
во' микропроцессора при относительной регистровой адре-
сации с применением регистра ВР по умолчанию адресо-
вать данные в сегменте стека. Типичная последователь-
ность выглядит следующим образом:
push bp
mov bp, sp
после чего первый параметр в стеке находится по адресу
[Ьр+4] или [bp-f-б] в зависимости от типа указателя на
функцию.
Важным является принятое соглашение об использо-
вании регистров. В функциях, написанных на языке
ассемблера, нельзя модифицироваь регистр ВР и в случае
установленной опции г (Use register variables — ON) —
также регистры SI и DI. Если функция возвращает 16-
битовую величину (char, short, int, enum, near указатель),
то она помещается в регистр АХ, 32-битовая величина
(включая указатели far и huge) — в паре регистров
DX:AX, причем в DX располагается старшее слово. Вели-
чины float и double возвращаются на вершине стека (TOS
или ST (0)) сопроцессора Intel 8087 или его эмулятора.
Перечисленная информация достаточна для разработ-
ки ассемблерных функций, компонуемых с программами на
языке СИ. Обычная последовательность действий вклю-
чает разработку и трансляцию ассемблерной функции (на-
пример, с получением объектного модуля asm_____c.obj),
затем необходимо перейти в среду ТУРБО СИ и создать
головной модуль с___asт.е, после чего следует создать
файл проекта (например, ca.prj), содержащий список всех
включаемых в проект модулей. Отличие этого файла проек-
та от традиционных заключается в том, что для всех мо-
дулей на СИ, вызывающих программы на языке ассембле-
303
ра, в круглых скобках через запятую должен быть указан
список объектных модулей с этими программами.
Приведем программу на СИ (файл с_________________________asm.с), вызывающую ас-
семблерную функцию addint, содержащуюся в файле asm__________________________с.asm:
linclude (stdio.h*
int pl,p2;
int extern cdecl addint)int,int):
aain()
{
scant ("PI:Ud\n* ,4pl);
scant)"P2:J4d\n',Ap2):
printf)’Cynna-Id\n",addint(pl,p2);
}
Функция addint осуществляет суммирование двух целых чисел и
возвращает целый результат:
.нот SHALL
.CODE
PUBLIC „addint
_addint
push bp ; BP адресует map
•ov bp.sp ; в стеке
•ov as,[bpvl] ; загрузка pl в AX
add as,ibpv6] ; в добавление p2
pop bp ; вшод
ret
„addint IHDP
Ш
Файл проекта ca. prj должен быть записан так:
с_ая (as>_c.obj)
assj.obj
8.9. ДРАЙВЕР СИМВОЛЬНОГО УСТРОЙСТВА
Рассмотрим пример драйвера символьного устройства,
связанного с дисплеем и клавиатурой. Он устанавливается
наряду со стандартным драйвером консоли, обслуживаю-
щим логическое устройство с именем CON, и поддерживает
работу устройства с логическим именем MRTICON. При
передаче файла в это устройство он выводится на дисплей,
причем управляющие коды возврата каретки и перевода
строки (13 и 10) отображаются в виде стрелки из элемен-
тов псевдографики. При чтении из устройства MRT1CON
символы, поступающие с клавиатуры, выводятся на экран
дисплея. Этот пример является учебным и предназначен
только для демонстрации.
В гл. 3 указывалось, что драйвер включает три части:
304
заголовок, стратегию и обработчик прерываний. Заголо-
вок содержит имя логического устройства (в нашем случае
это MRTIDRV), указатели на следующий драйвер, про-
грамму стратегии и обработчик прерываний. В заголовок
также входит слово, содержащее атрибуты устройства.
Программа стратегии получает управление от ОС и сохра-
няет в своей рабочей области указатель на заголовок за-
проса. Следующее обращение ОС происходит к обработчи-
ку прерываний, который постанавливает указатель на за-
головок запроса. Подобная идеология принята в ОС UNIX,
где программа стратегии загружает запросы в буфер, реа-
лизуя очередь запросов, а обработчик прерываний раз-
гружает буфер. В случае MS-DOS этот буфер сводится к
одному указателю.
Обработчик прерываний, получив указатель на заголо-
вок запроса, считывает из него номер функции и вызывает
нужную процедуру для ее выполнения. Для простейшего
символьного драйвера необходимо реализовать только три
функции: инициализацию (код 0); ввод (код 4); вывод
(код 8). Неустановленные функции должны завершаться
пересылкой константы 8103Н в поле статуса заголовка
запроса (т. е. драйвер работает нормально, ошибка, неиз-
вестная команда).
Функция инициализации применяется для определения
параметров установки драйвера, однако основное ее на-
значение состоит в сохранении адреса конца драйвера в
четырех байтах по смещению 14 в заголовке запроса. Эта
информация необходима системе для определения границы
свободной памяти.
Заголовок запроса для фукций ввода и вывода приве-
ден в гл. 3. Процедура вывода должна считать из заголов-
ка запроса адрес буфера и число байтов для передачи,
произвести операцию вывода данных в устройство и в
случае ее успешного завершения установить 8-й бит
(маска 100h) слова статуса в заголовке запроса. Процеду-
ра ввода работает аналогично, только происходит запись в
буфер.
Полный текст драйвера, содержащегося в файле
mrtidrv. asm, приведен ниже:
cseg segaeat para public 'code'
assme cs-caes.es-cses.da-cses
; Обвая чань эагошка запроса
rh_CBd eqn 2
rb_status equ 3
; Описание загоивка запроса для ввода » вавода
rhjoant eqn 18
305
rb.buf eqn U
; Описание заголовка запроса jjs инициализации
rb.brKjfs equ U
rhjrk.seg eqn 16
; Загиовок устройства
next.dev dd -1 ;в этой файю нет други! драйверов
attribute dn 8QQ3h ; сиивошое устройство, ввод, вывод
strategy dn dev_strategy ;адрео програиин стратегии
interrupt dn dev.interrupt ;адрес програиин обработки прерываний
dev_na«e db '№ICOH ' ;вин драйвера
; Рабочая область драйвера
rh_ofs du 1 ;снедение заголовка запроса
rh_seg du ? ссегиентный адрес заголовка запроса
sav db ? ;ддя ввода расаиреннык ASCII-кодов
; Программа стратегии
dev.strategy proc far
«ov cs:rh_seg,es сохранение сегментного адреса
«ov cs:rb_ofs,bx ; сохранение снедении
ret ;выход в DOS
dev.strategy endp
; Обработчик прерывания
dev.interrnpt proc far
cid рустановяа автоинкреиента
push ds ;сохранение значений регистров
pash es ;в стеке
pnsb ax
pash bx
pash ex
push dx
push di
push si
les bx.dword ptr csirh.ofs jesrbs на заголовок
гзапроса
«ov al.es: [bxerh_c«d] -.s ax
shl al,l ,-подучив иоиер
eb» ;коиаидн » 2
lea di.Mdtab ;в di - снедение
add di,ax -,програиин обсдухиваш
jip word ptr cs:[di] ;и переход на нее
; Таблица команд драйвера
CBdtab label word
du 1ШТШ1ШЮН
du SSDIA.C88CK
du GETJP8
de IOCTLJHFUT
du IBP0T
du ND-WPUr
du INPUT.STATUS
du imTjwsa
d» OUTPUT
du OUTPUTJERIFT
du OUTPUT-STATUS
du OUTPUT-FLUSH
du 1OCTL.OUT
306
du 0PE8
d» CLOSE
du КВ01Ш
du OUTPUT JUSY
; функция не чтрабатвааетсг
Ш1А.СВЕСК: jnp done
; Функция не отрабатывается
GETJPB: jsp done
; Функция не поддерживается
IOCTL_IHPUT: jap unknown
INPUT: bov cs.es'[bserhjoant] ;П01?ченне параметров
les di,ear[tarhjwf] ;нз загоювка запроса
read? bov aa,0 ;если был
xchg al.cs'sav ; расширенный
евр al.O ;А2СП-ход,
jne reads ;то запись в буфер
readZ; bov ah.O ;ввоД байта
int 16h ;с клавиатура
cup ax,9 ;с
je readZ гохнданнен
cap al.O ;если расширенный
jne reads ;А5С11-код, то
nov cs.'sav.ab ;сохранеяне его в s&v
readJ- stosb ; запись ь буфер
loop readl ГйГ1МС»зать еде?
les bx.deord ptr csrrh_ofs гвосстановление es:bx
jip done ;Функпнн выполнена
; Функция не отрабатывается
SDJSPUT- jap done
; Функция не отрабатывается
ISPST.SWTUS’W done
; Функция не отрабатываетси
ISPUTJLUSU - j«p done
OUTPOT:aov cx.es: (M+rb_conot} 1Й5 51,05: [bx+rhJ)Uf] <?ntl: lodsb cap al.Ddh jae out2 bov al,’< bov ah,Oeh int lOh loop outl jap done ont2: евр al.Oah jne nocrlf bov al,ч bov ah,Oeb int 10h eov ax.DeDdh int 10h bov ai.Oah nocrif:sov ah,Oeh int 10h loop ovtl jnp done тполученне параметров лэ заголовка запроса лтенне байта нз буфера если возврат каретки, ;то вывод ;стрелхн влево ;переход к следующему . ;байту геслн перевод строки, ; то гвавод уголка ;вшд возврата каретки ;н перевода строки ; вывод ; символа нз al
307
ООШТ.ШИУ: jsp ОСТРЯТ
; Фувши не 1ира6а»ваетсн
OBIPDTJTJWS: j«P done
; Функция не ирабатавается
OUTPUTJLDSBi jup done
; Функция не поддерживается
lOCTt.OOT: j«p cnknoss
; Функция не отрабатывается
OPEN' jnp done
, Функция не отрабатывается
CLOSE: jip done
; функаня не подчеркивается
fflOl'Aol-S: j»p паями
; Функции не подергивается
UTPDTJl'Sy- j»p ппкповп
, Обаяй выход нз функций драйвера
nnknonn: or wrd ptr es:[binrt.statnsj,8003k
done: or word ptr es' [tairh.statiis],0100b.
pop si ;восставовгение значений
pop di ^регистров из стека
pop ds
ЮР CK
pop ta
pop as
pop es
pop ds
ret
ISItlAUZJilOS'
pash cs ;вывод строки
pop ds счерез Функцию 9
bov ah,9 щрерывания
bov dx,offset ident ; 21h
int 21k
»ov Bord ptr es:[bx‘rkj>rk_ofsj,offset INITIALIZE!TON
bov word ptr es:[bnrhJrk_segLcs
jap done
ident db 10,13,13
db MRTI Console Driver ,10,13
db Минский радиотехнический институт’,10,13
db Кафедра ЭВМ ',10,13
db J’
dev-interrapt endp
cseg ends 8
end
После получения файла mrtidrv.exe следует преобра-
зовать его в файл драйвера с помощью системной утилиты
exe2bin:
С)exe2bin mrtidrv mrtidrv.sys (ВВОД)
Драйвер должен быть указан в файле CONFIG. SYS (см.
гл. 3) з
DEVICE = MRTIDRV.SYS
9. ИНСТРУМЕНТАЛЬНЫЕ СИСТЕМЫ
ПРОГРАММИРОВАНИЯ
9.1. ОБЩИЕ СВЕДЕНИЯ
Инструментальные системы создаются для того, чтобы
пользователю было удобно работать с выбранным языком
программирования. Большую популярность в настоящее
время получили интегрированные среды. Они являются
надстройкой над ОС и создают удобную рабочую обста-
новку. Организация и применение подобных средств рас-
сматриваются на примере ТУРБО систем программирова-
ния. Поскольку все они имеют общие черты и различаются
лишь некоторыми особенностями, присущими конкретному
алгоритмическому языку, остановимся лишь на одной из
таких систем — ТУРБО СИ (версия 2.0).
ТУРБО СИ использует быстрый и надежный компиля-
тор и включает две его различные версии: интегрирован-
ную среду (файл ТС.EXE) и отдельную автономную про-
грамму (файл ТСС.EXE), использующую командную
строку.
Рассмотрим запуск системы на ПЭВМ с жестким
диском (винчестером) достаточного объема. Для этих це-
лей организуем ряд подкаталогов. В первый из них (назо-
вем его CI) запишем файлы ТС.ЕХЕ, ТСС.ЕХЕ,
INSTALL.EXE (программа инсталляции, или начальной
установки системы) , TCHELP.TCH (файл для выдачи на
экран дисплея различных подсказок), СРР.ЕХЕ (макро-
процессор), TCINST.EXE (программа инсталляции для
файла ТС.ЕХЕ), TLINK.EXE (программа-компоновщик).
При работе только в интегрированной среде без файла для
выдачи подсказок можно записать лишь одну программу
ТС.ЕХЕ.
Во второй подкаталог (назовем его CIH) поместим
файлы с типом Н (*.Н.). Они содержат описания глобаль-
ных переменных и библиотечных функций, макроопределе-
ния, тексты стандартных сообщений и т. п.
В третий подкаталог (дадим ему имя CLIB) поместим
309
файлы типа LIB (*.LIB) и СО—.OBJ (объектный модуль
загрузчика). Обратите внимание на то, что в имени
СО —.OBJ второй знак — нуль, а не буква О (пятый
знак — буква О). Прочерк (—) в именах файлов заменяет
первую букву названия используемой модели памяти. По
умолчанию, задается модель Small (малая), и указанное
выше имя запишется в виде COS.OBJ. Файлы *.LIB задают
описание библиотечных функций. В их число входят:
MATH —.LIB — математические функции; EMU.LIB —
эмуляция чисел с плавающей точкой для сопроцессора
Intel 8087; FP87.LIB — функции сопроцессора Intel
8087; GRAPHICS.LIB — графические функции;
С —.LIB — другие функции.
Организуем также рабочий подкаталог (WORK), где
будем создавать собственные программы: *.С — исходные
тексты; *. OBJ — объектные модули; *.ЕХЕ — загрузочные
модули; *.PRJ — файлы проектов и др. Сюда же либо еще
в один выделенный подкаталог следует поместить файлы
*.BGI и *.CHR. Они необходимы для работы с графической
системой. Первую группу (ATT.BGI, CGA.BGI,
EGAVGA.BGI, HERC.BGI, IBM8514.BGI, PC3270.BGI)
составляют графические драйверы для различных дисп-
леев. Во вторую группу (GOTH.CHR, LITT.CHR,
SANS.CHR, TRIP.CHR) включены программы генерации
знаков для различных шрифтов.
Интегрированная версия ТУРБО СИ включает встроен-
ный файл конфигурации — TCCONFIG.TC, куда система
автоматически записывает параметры компилятора при их
сохранении (об этом будет подробнее сказано далее). За-
грузка интегрированной среды из подкаталога CI диска С
осуществляется командой:
С)С1\ТС (ВВОД)
После этого через 10—30 с на экране появляются главное
меню ТУРБО СИ и сведения о версии. Последние исчезают
после нажатия любой клавиши. Главное меню (рис. 9.1)
состоит из четырех частей: главного меню, окна редактора,
окна сообщений и строки оперативной подсказки.
В процессе работы пользователь может активизировать
то или иное окно на экране дисплея. Например, для выхода
в главное меню необходимо нажать клавишу Ф10 (F10).
Об этом напоминает подсказка в нижней части экрана.
Если активизировано меню, можно использовать более яр-
кую прописную букву для выбора соответствующего пунк-
310
FILE EDIT RUN COMPILE PROJECT OPTIONS DEBUG BRERK/WRTCH
[ФЙИЛ1 [РЕДАКТИРОВАНИЕ! [ВЫПОЛНЕНИЕ! [КОМПИЛЯЦИЯ! [ПРОЕКТ! [ПАРАМЕТРЫ! [ОТЛАДКА! [ПРОСМОТР!
-------------------------------------------- EDIT----------------.---------------------------—
LINE N COL М INSERT INDENT TAB | |
[СТРОКА Nl [КОЛОНКА Ml [ВСТАВКА! [АВТ0АБЗАЦ1 [ТАБУЛЯЦИЯ! ----------------
СПЕЦИФИКАЦИЯ
РЕДАКТИРУЕМОГО
ФАЙЛА
ОКНО РЕДАКТОРА
--- MESSAGE ---
[СООБЩЕНИЯ!
ОКНО СООБЩЕНИИ
^Fl-HELP F5-Z00M F6-SWITCH F7-TRACE F8-STEP Р9-МЙКЕ F10-MENU
[Ф1-П0М0ЩЫ [НАЛОЖЕНИЕ! [ПЕРЕКЛЮЧЕНИЕ! [ОТСЛЕЖИВАНИЕ! [Ф8-ШАГ1 [Ф9-С03ДАНИЕ1 [Ф10-ГЛЙВНОЕ МЕНЮ!
— СТРОКА ОПЕРЙТИВНОИ ПОДСКАЗКИ
Рис. 9.1. Главное меню системы программирования
та. Например, если пользователь находится в главном
меню и хочет войти в режим File, ему достаточно нажать
клавишу F. Того же эффекта можно добиться перемеще-
нием подкрашенного прямоугольника на наименование
соответствующего режима и последующим нажатием кла-
виши ВВОД. Перемещение осуществляется с помощью
клавиш со стрелками. Для выхода в предыдущее меню
достаточно нажать клавишу КЛЮЧ (ESC).
Находясь в любой точке КУРБО СИ, т. е. при активиза-
ции любого режима, можно получить оперативную
подсказку, характеризующую этот режим. Достаточно на-
жать клавишу Ф1 (F1), и на экране дисплея появится соот-
ветствующий текст.
Большие возможности предоставляет использование
оперативных клавиш. Независимо от того, какой режим
активизирован, нажатие их вызывает следующие дей-
ствия:
1) Ф1 (F1) —подсказка о текущем режиме;
2) Ф2 (F2) — сохранение на текущем диске файла,
находящегося в данный момент в редакторе;
3) ФЗ (F3) — загрузка файла (при этом появляется
запрос о его имени);
4) Ф4 (F4) — выполнение в режиме отладки строки
программы, в которой находится курсор;
5) Ф5 (F5) —наложение активных окон друг на друга
либо снятие наложения. В последнем случае площадь
экрана для набора информации увеличивается;
6) Ф6 (F6) — смена активного окна (наиболее часто
эта клавиша используется для выхода в режим редактиро-
вания текста);
7) Ф7 (F7) — выбор очередной строки программы при
отладке (см. пп. Trace into в § 9.5);
8) Ф8 (F8) — выбор очередной строки программы при
отладке (см. пп. Step over в § 9.5);
9) Ф9 (F9) — создание выполняемого файла (типа
EXE);
10) Ф10 (F10) — активизация главного меню;
11) ДОП — Ф1 (Alt — Fl) —активизация предыду-
щего экрана подсказки;
12) ДОП—ФЗ (Alt — F3) —выбор файла для за-
грузки;
13) ДОП— Ф5 (Alt — F5) —просмотр результатов
выполненных программ (последней программы и предыду-
щих, для которых результаты помещаются на одном
экране);
312
14) ДОП — Ф9 (Alt — F9) — построение объектного
файла (типа OBJ) для программы, загруженной в
редактор;
15) ДОП —Ф10 (Alt — F10) —выводит на экран
информацию о версии системы программирования;
16) ДОП—В (Alt — В) — активизация меню
Break/watch (просмотр активизированных переменных);
17) ДОП — С (Alt — С) —активизация меню Com-
pile (трансляция);
18) ДОП — D (Alt — D) — активизация меню Debug
(отладка);
19) ДОП — Е (Alt — Е) — активизация редактора;
20) ДОП — F (Alt — F) — активизация меню File
(работа с файлами);
21) ДОП— О (Alt — О) —активизация меню Op-
tions (параметры);
22) ДОП—Р (Alt — Р) —активизация меню Pro-
ject (проект);
23) ДОП —R (Alt — R) —активизация меню Run
(выполнение);
24) ДОП—X (Alt —X) — выход из ТУРБО СИ в
среду ОС;
25) УПР — Ф2 (Ctrl — F2) —прерывание выполне-
ния программы в режиме отладки (см. пп. Program reset в
§ 9.5);
26) УПР — ФЗ (Ctrl — F3) — отображение содержи-
мого стека, показывающего последовательность вызова
подпрограмм (см. пп. Call stack в § 9.5);
27) УПР—Ф4 (Ctrl — F4) вывод окна для задания
переменным определенных значений. Переменные могут
входить в выражения. Здесь же отображается новое вы-
численное значение переменных либо выражения (см. пп.
Evaluate в § 9.5);
28) УПР — Ф7 (Ctrl — F7) — активизация новой пе-
ременной или выражения для отладки программы (см. пп.
Add watch в § 9.5);
29) УПР — Ф8 (Ctrl — F8) — установка контрольной
точки в программе (см. пп. Toggle breakpoints в
§ 9.5);
30) УПР — Ф9 (Ctrl — F9) — запуск текущей про-
граммы на выполнение.
В процессе работы из основного экрана (см. рис. 9.1)
можно активизировать подчиненное меню, например нажа-
тием двух клавиш ДОП —С (Alt—С). Подчиненные
меню включают команды и переключатели. Команды вызы-
313
вают выполнение некоторых действий (загрузка файла,
компиляция, сохранение файла и т. и.). Переключатели
включают (оп) либо выключают (off) различные режимы
работы системы программирования, С их помощью можно
также выбрать один из нескольких режимов. Для этого
закрашенный прямоугольник устанавливается на требуе-
мые заголовки в подчиненных меню и нажимается клавиша
ВВОД (Entry). Такие действия производятся до тех пор,
пока не будет выбран нужный режим.
Проиллюстрируем сказанное примером. ТУРБО СИ
позволяет оптимизировать программу либо по быстродей-
ствию (по скорости — Speed), либо по объему занимаемой
памяти (по размеру — Size). Покажем, как включить тот
или иной режим. Сначала необходимо выбрать режим
Options. В результате на экране дисплея появится первое
подчиненное меню. С помощью клавиш со стрелками не-
обходимо наложить выделенный прямоугольник на слово
Compiler и нажать клавишу ВВОД — на экране появится
второе подчиненное меню. Точно так же выбирается
третье подчиненное меню (пп. Optimization). Затем необ-
ходимо наложить выделенный прямоугольник на строку
Optimize for Size и нажать клавишу ВВОД. Вместо этой
строки на том же месте появится новая строка Optimize
for Speed, и требуемый режим установлен.
В главном меню только один режим, не вызывающий
подчиненные меню,—это Edit (редактор), который вклю-
чает редактор текста для подготовки и корректировки про-
грамм.
Охарактеризуем другие режимы главного меню:
1) File — работа с файлами: загрузка, сохранение, вы-
бор, создание и т. п.; работа с каталогами: изменение,
просмотр; выход из программы и вызов ОС;
2) Run — для выполнения программы, прерывания ее
выполнения и пошагового просмотра ее результатов в ре-
жиме отладки; :
3) Compile — трансляция программы в объектный и
выполняемый файлы;
4) Project — для указания файлов, включаемых в про-
грамму, и управления проектом ее создания;
5) Options —для выбора параметров инструменталь-
ной системы программирования: модели памяти, рабочего
окружения и т. п. Записывает маршруты для поиска
исходных текстов программ, библиотечных и включаемых
файлов. Позволяет сохранить параметры компилятора и
загружает их из файла конфигурации (TCCONFIG.TC);
314
6) Debug — позволяет задавать различные режимы
для отладки программ;
7) Break/watch — позволяет выбирать переменные в
программе, значения которых контролируются в процессе
ее отладки.
9.2. РАБОТА С ФАЙЛАМИ
При активизации режима Edit перед загрузкой кон-
кретного файла редактор автоматически присваивает ему
имя NONAME.C. Далее можно выполнять следующие
действия:
1) создать новый файл, сохранив имя NONAME.C.
либо выбрав любое другое имя;
2) загрузить с магнитного диска и начать редактиро-
вание существующего файла;
3) выбрать файл из списка редактируемых файлов и
загрузить его в окно редактора;
4) сохранить на магнитном диске находящийся в окне
редактора файл;
5) переходить из окна редактора в окно сообщений
для нахождения и коррекции ошибок, полученных во
время трансляции.
При создании и редактировании нового файла окно
сообщений не нужно. Для того чтобы расширить окно
редактора на весь экран, необходимо нажать клавишу Ф5
(F5). Возврат в режим наложения экранов осуществляет-
ся повторным нажатием клавиши Ф5 (F5).
На рис. 9.2 показано подчиненное меню для режима
File. Создание нового файла осуществляется одним из двух
способов:
1) выбором режима New и нажатием клавиши
ВВОД. В результате реализуется выход в редактор и соз-
данному файлу назначается имя NONAME.C;
2) выбором режима Load, после чего появляется пря-
моугольник-подсказка, в который необходимо вписать имя
файла (того же эффекта можно достигнуть, нажав клави-
шу ФЗ (F3)).
Для загрузки существующего на магнитном диске фай-
ла можно воспользоваться режимами Load и Pick подчи-
ненного меню. В первом случае в прямоугольник-под-
сказку необходимо вписать спецификацию того файла, ко-
торый требуется загрузить. Вместо спецификации можно
задать шаблон имени файла и затем выбрать конкретный
файл с помощью клавиш со стрелками. Режим Pick позво-
315
FILE
(ФАЙЛ)
LOAD ’ F3 _______
(ЗАГРУЗКА ФЗ)
PICK ALT—F3-
t ВЫБОР ДОП—ФЗ)
NEV -------------
(НОВЫЙ)
НАБРАТЬ НА КЛАВИАТУРЕ
ИМЯ ФАЙЛА
---------------- -1_> РЕДАКТИРОВАНИЕ
____________________1_ФАЙЛА
-►ОКНО С ИМЕНАМИ ----► ВЫБОР ТРЕБУ-
ФАИЛОВ ЕМОГО ФАЙЛА
-►РЕДАКТИРОВАНИЕ ФАЙЛА NONAME.С
SAVE -------------►СОХРАНЕНИЕ РЕДАКТИРУЕМОГО
(СОХРАНИТЬ) ФАЙЛА
WRITE ТО----------►ЗАПИСЬ ФАЙЛА ПОД НОВЫМ ИМЕНЕМ
(ЗАПИСАТЬ В) ИЛИ НА МЕСТО СУЩЕСТВУНИЦРГО ФАЙЛА
DIRECTORY---------►ВЫВОД НА ЭКРАН СПИСКА ФАЙЛОВ
(ДИРЕКТОРИИ)
CHANCE OIR--------►ИЗМЕНЕНИЕ ТЕКУЩЕГО ДИРЕКТОРИЯ
(ИЗМЕНИТЬ ДИРЕКТОРИЙ)
OS SHELL----------►ВРЕМЕННЫЙ ВЫХОД В ОС
(ЯДРО ОС)
QUIT ALT—-X ------►ВЫХОД В ОС
(выход доп—х)
Рис. 9.2. Подчиненное меню для режима File
ляет быстро выбрать с помощью клавиш со стрелками один
из ранее загружавшихся файлов.
Сохранение редактируемого файла на текущем диске
осуществляется выбором режима Save. Текст, находящий-
ся в окне редактора, может быть записан как новый файл
или на место уже существующего. Его можно специфици-
ровать по усмотрению пользователя с помощью режима
Write.to. Новую спецификацию файла необходимо вписать
в прямоугольник-подсказку режима Write to и нажать кла-
вишу ВВОД (по умолчанию, принимается тип С). Если не
нужно указывать тип файла, после имени ставится точка
(например, PRIM.). Когда файл записывается на место су-
ществующего, на экране появляется сообщение с просьбой
подтвердить намерения. На него следует ответить Y (да),
если пользователь согласен с записью файла на место су-
ществующего, и N (нет), если эти действия необходимо
отменить.
Подрежим Directory позволяет вывести на экран дис-
плея список файлов из указанного каталога. При его выбо-
ре появляется прямоугольник-подсказка, куда следует
вписать маршрут к каталогу и имя или шаблон для файлов.
Как и выше, команда будет выполнена после нажатия кла-
виши ВВОД.
316
Подрежим Change dir позволяет указать новый марш-
рут к каталогу, где хранятся исходные тексты редактируе-
мых программ на языке СИ. Для этого в прямоугольник-
подсказку вписывается требуемое имя и нажимается кла-
виша ВВОД.
Подрежим Os shell позволяет осуществить временный
выход из ТУРБО СИ в ОС. Для возврата в среду ТУРБО
СИ необходимо набрать и ввести команду Exit.
Подрежим Quit прекращает работу с ТУРБО СИ и реа-
лизует выход в ОС.
9.3. ПОДГОТОВКА И РЕДАКТИРОВАНИЕ
ТЕКСТОВ ПРОГРАММ
Подготовка и корректировка исходных текстов про-
грамм осуществляются с помощью встроенного экранного
редактора текста. После загрузки существующего либо
создания нового файла активизируется режим Edit. При
этом в верхней части экрана появляется двойная горизон-
тальная черта. Кроме основной части окна редактора, в
которой обрабатывается текст, имеются еще две информа-
ционные строки (см. рис. 9.1): Line п, Col m, Insert,
Indent, Tab, спецификация редактируемого файла. Оха-
рактеризуем слова, записанные в этой строке:
1) Line п — указывает, что курсор находится в строке
редактируемого текста с номером п;
2) Col m — указывает, что курсор находится в m-й по-
зиции выбранной строки;
3) Insert — включен режим вставки. В результате лю-
бой введенный символ помещается на место курсора, а
соответствующий текст сдвигается вправо на одну пози-
цию. Этот режим переключается нажатием клавиши
ВСТ (1ns) либо одновременно двух клавиш УПР — V
(Ctrl —V). После переключения устанавливается ре-
жим Overwrite (затереть). В результате любой знак по-
мещается вместо символа, на который указывает кур-
сор;
4) Indent — включен режим автоабзаца. Он переклю-
чается с помощью клавиш УПР — О — I (Ctrl — О — I).
Когда автосмещение включено, после нажатия клавиши
ВВОД курсор переводится не в начало следующей строки,
а в ее позицию, совпадающую с позицией первого видимо-
го символа предыдущей строки;
5) Tab — включен режим табуляции. Он переключает-
ся с помощью клавиш УПР — О — Т (Ctrl — О — Т);
317
6) спецификация файла — указываются маршрут, имя
и тип для редактируемого файла.
Команды редактора ТУРБО СИ приведены в табл. 9.1.
Таблица 9.1
Команда Назначение
1 2
Команды управления курсором
УПР—S (Ctrl—S) Перемещение курсора на позицию влево
УПР —D (Ctrl — D) Перемещение курсора на позицию вправо
УПР —A (Ctrl —А) Перемещение курсора на слово влево
УПР — F (Ctrl —F) Перемещение курсора на слово вправо
УПР —Е (Ctrl — Е) Перемещение курсора на строку вверх
УПР —X (Ctrl —X) Перемещение курсора на строку вниз
УПР—W (Ctrl—W) Перемещение текста на строку вниз
УПР—Z (Ctrl—Z) Перемещение текста на строку вверх
УПР — R (Ctrl — R) Перемещение текста на страницу вверх
УПР —С (Ctrl—С) Перемещение текста на страницу вниз
УПР —Q—S (Ctrl—Q—S) Перемещение курсора в начало строки
УПР —Q—D (Ctrl —Q—D) Перемещение курсора в конец строки
УПР —Q—Е (Ctrl—Q—Е) Перемещение курсора в начало страницы
УПР—Q—X (Ctrl —Q—X) Перемещение курсора в конец страницы
УПР—Q—R (Ctrl—Q—R) Перемещение курсора в начало файла
УПР —Q—С (Ctrl—Q—С) Перемещение курсора в конец файла Перемещение курсора в начало блока
УПР —Q—В (Ctrl— Q— В)
УПР —Q—К (Ctrl—Q—К) Перемещение курсора в конец блока
УПР —Q—Р (Ctrl—Q—Р) Перемещение курсора в позицию, где он находился перед последней командой
Команды вставки и удаления
УПР—V (Ctrl—V) Включить/выключить режим вставки
УПР —N (Ctrl — N) Вставить строку
УПР—Y (Ctrl —Y) 318 Удалить строку
Окончание табл. 9.1
УПР—Q—Y (Ctrl—Q— Y)
УПР—Н (Ctrl—Н)
УПР—G (Ctil—G)
УПР—T (Ctrl — Т)
Удалить символы до конца строки
Удалить символ слева от курсора
Удалить символ под курсором
Удалить слово справа от курсора
Команды
УПР —К—В
УПР —К—К
УПР —К—Т
УПР —К—С
УПР—К—Y
УПР —К—Н
УПР—К—V
УПР —К—R
упр—к—w
УПР—К—Р
(Ctrl -К —В)
(Ctrl —к— К)
(Ctrl —к—Т)
(Ctrl—К—С)
(Ctrl—-К — Y)
(Ctrl — К—H)
(Ctrl —к—V)
(Ctrl-к- R)
(Ctrl—к—W)
(Ctrl —к—P)
для работы с блоками
Отмегигь начало блока
Отметить конец блока
Отметить единственное слово как
блок
Копировать блок
Удалить блок
Включить/выключнть индикацию
блока
Переместить блок
Прочитать блок с диска
Записать блок на диск
Вывод блока на принтер (если блок
не отмечен, выводится текст всей про-
граммы )
Смешанные команды
УПР —и (Ctrl —U)
УПР —O—I (Ctrl—0—1)
УПР —Р (Ctrl —Р)
УПР —Q—F (Ctrl—Q—F)
УПР —Q—A (Ctrl—Q—А)
УПР — Q—н (Ctrl — Q—п)
УПР —К—D (Ctrl—К —D)!
УПР—К—Q (Ctrl —К—Q)/
УПР —L (Ctrl —L)
УПР —Q—L (Ctrl —Q—L)
УПР — K— S (Ctrl — K—S)
УПР — K—n (Ctrl— K— n)
УПР—I (Ctrl—I)
УПР —О—T (Ctrl —О—T)
Прекратить выполнение команды
Включить/выключнть режим авто-
абзаца
Проверить конфигурацию символа
Найти
Найти и заменить
Найти место метки в тексте (п —
цифра от 0 до 3)
Выход из режима редактирования
без сохранения текста
Повторить последний поиск
Восстановить строку
Сохранить текст
Установить метку (п — цифра от
О до 3)
Табуляция
Включен ие/выключение табуляции
В процессе редактирования текста часто возникает не-
обходимость введения, удаления, перемещения довольно
больших фрагментов, называемых блоками. Блок — лю-
бой фрагмент текста, начиная с одного знака и кончая
сотнями строк. Одновременно можно выделить только один
блок. Для этого отмечаются его начало и конец. После
выделения текст в блоке будет подсвечен. Далее его можно
записать на диск, прочитать с диска и поместить в любое
319
место программы, переместить, создать копию в программе
и т. п.
Команды УПР — Q — F (Найти) и УПР — Q — А
(Найти и заменить) требуют дополнительных пояснений.
По команде «Найти» производится поиск строки. Она мо-
жет содержать не более 30 символов и вводится в ответ на
сообщение Find. После набора строки нажимается клави-
ша ВВОД. Затем запрашиваются режимы поиска (Op-
tions). Здесь возможны следующие указания пользова-
теля:
В — поиск в обратном направлении (от места курсора
к началу файла);
Q — поиск по всему файлу (независимо от места
курсора);
N — поиск в прямом направлении (от места курсора к
концу файла);
п —если п целое число, найти п-е появление искомой
строки;
U — игнорировать различие между строчными и про-
писными буквами;
W — осуществлять поиск только целых слов.
Требуемый режим задается совокупностью этих симво-
лов (например, Options: GU), после чего нажимается кла-
виша ВВОД.
Команда «Найти и заменить» выполняется практически
так же, за исключением того, что дополнительно запраши-
вается новая строка (для замены): Replace with:. Ее длина
тоже не должна превышать 30 символов. При положитель-
ном исходе поиска на экране появляется сообщение
Replace (Y/N). Необходимо ответить Y (да), если требует-
ся замена, и N (нет) — в противном случае. Рассмотрен-
ные выше опции реализуются так же, как и в команде
«Найти». Режим N определяет замену без подтверждений
(типа Y/N). Режим п означает необходимость выполнения
п замен. «:
9.4. НАСТРОЙКА СИСТЕМЫ
Рассмотрим действия, которые могут быть выполнены
для установки параметров рабочего окружения ТУРБО
СИ. Для этого необходимо указать все каталоги с систем-
ными программами (файлы типа LIB и Н, файл
СО—.OBJ и т. п.). Выполнение подобных действий осу-
ществляется в такой последовательности:
1) активизируется режим Options и его подрежим
Directories;
320
2) в подрежиме Directories выбирается пункт Include
directories и нажимается клавиша ВВОД. После этого
устанавливается маршрут к файлам типа Н и нажимается
клавиша ВВОД. В результате система будет знать, где
находятся включаемые файлы *.Н;
3) аналогично выбирается пункт Library directories и
устанавливается маршрут к файлам типа LIB и файлу
COS.OBJ;
4) в пункте Output directory указывается маршрут к
каталогу, в который будут записываться выходные файлы
(полученные выполняемые программы);
5) в пункте Turbo С directory записывается маршрут к
системным файлам ТУРБО СИ. Этот каталог ТУРБО СИ
используется для поиска заданных по умолчанию файлов:
конфигурации (TCCONFIG.TC), PICK файла (TCPICK.
TCP; здесь содержится информация о последних восьми
файлах пользователя), помощи (TCHELP.TCH);
6) в пункте Pick file name можно указать имя файла, в
котором будут сохраняться параметры рабочего окруже-
ния (при загрузке ТУРБО СИ они будут автоматически
установлены).
Другие подрежимы меню Options позволяют устано-
вить параметры, определяющие работу компонентов ТУРБО
СИ (управление работой компилятора и компоновщика,
изменение директориев включаемых и библиотечных фай-
лов, задание аргументов, передаваемых выполняемой про-
грамме, ит. п.) Охарактеризуем пункты этого меню.
Подчиненное меню Compiler (компилятор) позволяет
установить требуемую конфигурацию аппаратуры, задать
модель памяти, способ отладки и оптимизации получаемой
программы, управление диагностическими сообщениями и
макроопределениями. Подпункт Model (модель) позволяет
выбрать одну из существующих в ТУРБО СИ моделей
памяти: Tiny (минимальную), Small (малую). Compact
(компактную), Medium (среднюю), Large (большую), Hu-
ge (максимальную). По умолчанию, установлен размер
Small. В модели Tiny все четыре сегментных регистра
микропроцессора (CS, DS, SS, ES) содержат один и тот
же код, поэтому 64 К байт выделяются для хранения про-
грамм и данных. В настоящее время необходимость в
подобных программах вызвана тем, что их можно преобра-
зовать к типу СОМ с помощью утилиты EXE2BIN (см. гл.
3). В модели Small регистры CS и DS содержат различные
коды, и можно использовать 64 К байт памяти для про-
грамм и 64 К байт — для данных (всего 128 К байт). Мо-
11 Скляров В А
321
дель Compact полезна для малых программ (помещаемых
в одном сегменте) с большим объемом данных. В ней
используются указатели типа near для кода и указатели
типа far для данных. Модель Medium, наоборот, полезна
для больших программ с малым объемом данных (все вы-
зовы функций реализуются через указатели типа far, а
объем данных ограничен одним сегментом). Модель Large
применяет указатели типа far для программы и данных.
Она позволяет использовать всю память ПЭВМ. Глобаль-
ные переменные могут находиться в своем сегменте раз-
мером до 64 К байт. Стек тоже может использовать свой
сегмент (64 К байт). Модель Huge подобна модели Large,
за исключением того, что пространство для глобальных пе-
ременных может занимать память объемом более 64 К
байт. Подпункт Defines (определения) позволяет передать
макропроцессору различные макроопределения. Несколь-
ко из них могут быть разделены точкой с запятой. В приве-
денном ниже примере определяются имя Novosibirsk и пе-
ременная х, равная нулю:
Novosibirsk; х = О
Параметры пункта Code generation (генерация кода)
определяют различные варианты генерации объектного ко-
да. Здесь можно: задать последовательность вызова под-
программ, соответствующую СИ или ПАСКАЛю (Calling
convention); указать тип микропроцессора (Instruction
set), на котором будет исполняться программа (8088/8086
или 80186/80286); способ обработки чисел с плавающей за-
пятой (None— нет, Emulation —эмуляция, 8087/80287—
сопроцессор); определить по умолчанию в программе сим-
вольный тип (Default char type) — Signed (знаковый) или
Unsigned (беззнаковый), в результате чего будет принято
signed char или unsigned char; выбрать выравнивание в
памяти (Aligment) по словам (Word) или по байтам
(Byte); реализовать генерацию подчеркиваний (Generate
underbars); осуществить слияние одинаковых строк для
уменьшения размера программ (Merge duplicate strings);
генерировать стандартный кадр стека (Standart stack
frame); осуществить проверку переполнения стека (Test
stack overflow); включить номера строк в объектный файл
для использования их отладчиком исходного текста (Line
numbers); занести информацию для отладчика в получае-
мые объектные модули программ (OBJ debug information).
При использовании отладчика переключатель в данном
пункте должен быть установлен в состояние «оп».
322
Параметры пункта Optimization определяют различные
пути оптимизации программ. Здесь можно назначить
оптимизацию (пункт Optimize for) по скорости (Speed)
либо по объему программы (Size); задать использование
либо неиспользование внутренних регистров микропроцес-
сора (Use register variables); включить регистровую опти-
мизацию (Register optimization); выполнить оптимизацию
переходов (Jump optimization),
Параметры пункта Source (источник) определяют спо-
соб интерпретации исходного текста на начальных фазах
компиляции. Здесь можно указать: количество значащих
символов в идентификаторе (Identifier length) от 1 до 32
(по умолчанию, принято 32); возможность использования
вложенных комментариев (Nested comments); необходи-
мость исключения всех зарезервированных слов языка СИ,
не соответствующих американскому стандарту ANSI.
Параметры пункта Errors (ошибки) позволяют опреде-
лять, как компилятор реагирует на сообщения об ошиб-
ках и что он с ними делает. Здесь можно указать: после
какого количества ошибок (Errors) в пределах от 0 до
255 прекращается компиляция (по умолчанию, принято
25); после какого количества предупреждений (Warnings)
в пределах от 0 до 255 прекращается компиляция (по
умолчанию, принято 100); возможность вывода преду-
преждений (до 27) на экран дисплея (Display warnings).
В подпункте Names (имена) можно изменить присваивае-
мые по умолчанию имена сегментов (Code names, Data
names, BSS names).
Подчиненное меню Linker (компоновщик) позволяет
установить параметры компоновщика. Здесь может быть:
выбран тип Мар файла (Map file), который будет получен
в процессе компоновки (Off, Segment, Publics, Detailed);
включена инициализация сегмента (Initialize segments);
задан режим Default libraries (библиотеки по умолча-
нию). Если последний режим включен (оп), компоновщик
будет пытаться найти неопределенные символы не только в
библиотеках ТУРБО СИ. В подпункте Graphics library
(графическая библиотека) разрешается или запрещается
подключение файла GRAPHICS.LIB. В режиме off с гра-
фическими функциями ТУРБО СИ работать запрещено.
Подпункт Warn duplicate symbol (предупреждение о дуб-
лировании символов) является переключателем. В режи-
ме оп компоновщик будет предупреждать о дублировании
символов в объектных и библиотечных файлах. Под-
пункт Stack warning (предупреждение об ошибках в
323
стеке) задает возможность выдачи компоновщиком соот-
ветствующих предупредительных сообщений (No stack).
Подпункт Case-sensitive link (компоновка с учетом регист-
ра) позволяет включить (оп) либо выключить (off) режим,
при котором различаются прописные и строчные буквы. По
умолчанию, этот режим включен, так как СИ — язык,
где одноименные строчные и прописные символы опреде-
ляют разные объекты.
Подчиненное меню Environment (окружение) позво-
ляет устанавливать дополнительные параметры рабочего
окружения системы. Подпункт Message Tracking (отсле-
живание сообщений об ошибках) имеет три подрежима:
Current File (текущий файл) — ошибки будут отслежи-
ваться только в текущем файле (находящемся в окне
редактора); All Files (все файлы) —отслеживание будет
вестись по всем файлам, для которых есть сообщения об
ошибках; off (выключено) —сообщения не будут отсле-
живаться. Подпункт Keep messages (сохранять сообще-
ния) в режиме off автоматически удаляет все сообщения
перед новой компиляцией. В режиме оп сообщения сохра-
няются. Подпункт Config auto save (автоматическое сох-
ранение конфигурации) в режиме оп задает автоматиче-
ское сохранение текущих параметров рабочего окружения
при запуске программы на выполнение либо при выходе в
ОС. Подпункт Edit auto save (автоматическое сохранение
текущего файла) выполняет те же действия, что и Con-
fig auto save по отношению к текущему файлу. Подпункт
Backup files' (создание резервного файла) позволяет соз-
давать (оп) либо не создавать (off) резервные файлы типа
ВАК- Подпункт Tab size (параметры табуляции) позво-
ляет устанавливать табуляцию в диапазоне от 2 до 16.
Подкункт Zoomed windows (наложение окон) включает
(оп) и выключает (off) режим наложения окон (выпол-
няются те же действия, которые задаются клавишей
Ф5). Подпункт Screen size, (размер экрана позволяет
установить режим отображения 25 строк на эк-
ран (25 line display), 43 строк на экран для адаптера
EGA и 50 строк на экран для адаптера VGA (43/50 line
display).
Пункт Arguments (аргументы) позволяет передавать
работающей программе аргументы из командной строки
(так же, как это делается при вызове программ в среде
ОС). Здесь имя программы указывать не нужно и следует
задавать только одни аргументы.
Пункт Save options (сохранить параметры) позволяет
324
сохранить параметры рабочего окружения в файле кон-
фигурации (по умолчанию, имя этого файла
TCCONFIG.TC).
Пункт Retrieve options (восстановить параметры)
позволяет загрузить файл конфигурации.
По умолчанию, в ТУРБО СИ задан стек размером
4096 байт. Он определяется значением глобальной пере-
менной __stklen. Чтобы изменить размер стека, например
до величины 12000 байт, необходимо в программе на языке
СИ записать следующую строку:
extern unsigned _stklen = 12000;
9.5. КОМПИЛЯЦИЯ, ОТЛАДКА
И ВЫПОЛНЕНИЕ ПРОГРАММ
Для компиляции и выполнения программы используют-
ся пункты Run (выполнение) и Compile (компиляция)
главного меню. В пункте compile есть следующие ре-
жимы:
1) Compile to OBJ — команда трансляции исходного
текста в объектный файл. В строке этого подпункта все-
гда находится спецификация файла, полученного в резуль-
тате трансляции. Она образуется на основе первичного
исходного файла (Primary С file), а если он не задан,— на
основе последнего файла, загружавшегося в редактор;
2) Make EXE file — команда построения выполняемого
файла. В этом пункте всегда высвечивается спецификация
полученного модуля;
3) Link EXE file — команда компоновки текущего
объектного файла с библиотеками (*.LIB), в результате
получается новый выполняемый файл;
4) Build all — команда перетрансляции всех файлов
проекта, независимо от даты их образования;
5) Primary С file — команда для указания имени фай-
ла, который должен транслироваться в объектный код при
выполнении команды Compile to OBJ;
6) Get info — команда, выдающая в окно на экране
дисплея информацию о текущем файле, результатах по-
следней компиляции или выполнения программы, некото-
рых параметрах ПЭВМ. Там указываются имя текущего
каталога (Current directory), имя текущего файла (Cur-
rent file), размер файла (File size), число скомпилиро-
ванных линий (Lines compiled), число предупреждений
(Total warnings), число ошибок (Total errors), объем до-
ступной памяти (Available memory) и т. п.
Рассмотрим режим пункта Run:
325
1) Run — команда, задающая компиляцию, компонов-
ку и выполнение программы. Аналогичные действия вы-
полняются по команде УПР — Ф9 (Ctrl — F9);
2) Program reset — команда, предназначенная для
использования при повторном запуске программы в режи-
ме отладки. Аналогичные действия выполняются по коман-
де УПР — Ф2 (Ctrl — F2);
3) Go to cursor — команда, вызывающая при выполне-
нии программы переход от текущей строки к строке, в
которой находится курсор (к местоположению курсора).
Используется в режиме отладки. Аналогичные действия
выполняются по команде Ф4 (F4);
4) Trace into — команда, задающая выполнение сле-
дующей строки в текущей функции ТУРБО СИ. При вызо-
ве функции (являющейся подпрограммой) строки после-
довательно просматриваются внутри этой функции. Если в
одной строке записано несколько команд языка СИ, все
они за один шаг выполняются одновременно. Используется
при отладке. Аналогичные действия выполняются по ко-
манде Ф7 (F7);
5) Step over — команда, задающая выполнение сле-
дующей строки в текущей функции без перехода в другую
функцию, вызываемую из этой функции. Все действия в
вызванной функции считаются выполненными при обра-
щении к соответствующей строке (с вызовом функции).
Используется при отладке. Аналогичные действия выпол-
няются по команде Ф8 (F8);
6) User screen — команда, выполняющая те же дей-
ствия, что и ДОП —Ф5 (Alt — F5).
Предположим, что разрабатывается программа с
именем PROG. Все, что необходимо сделать для этого,
можно представить в виде следующей простой схемы:
PROG.С -> PROG.OBJ -> PROG.EXE. Сначала нужно
создать файл PROG.С, затем в редакторе набрать текст
соответствующей программы и записать его "в этот файл.
После этого выполняется компиляция программы и обра-
зуется объектный файл (PROG.OBJ). На последней ста-
дии после подключения компоновщика строится выполняе-
мый файл (PROG.EXE). Его уже можно загружать и вы-
полнять в ПЭВМ. После набора текста программы
PROG.С в окне редактора, ее трансляция, компоновка,
загрузка и выполнение могут быть произведены совсем
просто. Для этого достаточно нажать клавиши УПР — Ф9
(Ctrl — F9). Система заносит информацию компилятора
и компоновщика в буфер, а затем выводит ее на экран в
326
окне сообщений, позволяя одновременно просматривать
эти сообщения (об ошибках и предупреждениях) и редак-
тировать текст программы.
Если в результате компиляции обнаружены ошибки, на
экран будет выведена строка Press any key (нажмите лю-
бую клавишу). После выполнения рекомендуемых дей-
ствий появится окно сообщений. При этом будут выделены
как сообщение об ошибке, так и вызвавшая его неправиль-
ная строка текста программы (в окне редактора). Для про-
смотра других сообщений необходимо воспользоваться
клавишами со стрелками.
ТУРБО СИ обеспечивает раздельную компиляцию не-
скольких исходных файлов. Это достигается средствами
создания проектов. При построении программы из несколь-
ких исходных файлов необходимо указать компилятору,
какие программы используются. Предположим, что есть
два файла: первый содержит основную программу
(PROG1.C); второй—подпрограмму (PROQ2.C). Тогда
можно составить проект, который будет содержать всего
две строки с именами файлов:
PROG1
PROG2
Назовем файл проекта PROG.PRJ. В отношении строк
PROG1 и PROG2 следует напомнить, что для любого
файла без расширения подразумевается тип С (хотя мож-
но было и записать PROG 1.С, PROG2.C). Кроме того, по-
следовательность перечисления файлов не имеет значения,
влияя лишь на очередность их трансляции. Имя выполняе-
мой программы будет устанавливаться по имени файла
проекта (т. е. в примере PROG.EXE). В проекте можно
указывать маршрут к любой программе, поэтому совер-
шенно не обязательно располагать все исходные файлы в
одном каталоге.
Имя PROG.PRJ необходимо ввести в меню работы с
проектом. Для этого нужно выбрать подрежим Project
name режима Project и задать маршрут и составное имя
соответствующего файла. Имя проекта можно указывать
явно, а также воспользоваться шаблоном для нахождения
его в каталоге, который появится на экране дисплея. Далее
выполняются те же действия, что и для обычного файла
типа С, загруженного в редактор.
Соединять можно и программы, являющиеся объектны-
ми файлами. Если одна из них написана на языке ассемб-
лера, необходимо учесть замечания, изложенные в гл. 8.
327
Пусть, например, к программе на СИ MYPROG.C на этапе
компоновки должна быть подключена программа на
АССЕМБЛЕРе MYASM.OBJ. Последний файл уже полу-
чен с помощью компилятора MASM.EXE, для чего ранее
была выполнена команда вида
C)MASM/mx MYASM <ВВОД>
В этом случае необходимо создать такой PRJ файл:
MYPROG (MYASM.OBJ)
MYASM.OBJ
Имя PRJ файла (например, MY.PRJ) устанавливается
в подрежиме Project. Далее производятся компоновка,
загрузка и выполнение программы (например, путем на-
жатия клавиш Ctrl — F9).
Охарактеризуем другие пункты режима Project:
1) Break make on — команда, дающая возможность
указать, когда должна прерваться работа: после трансля-
ции файла (в котором обнаружены ошибки, предупреж-
дения, фатальные ошибки) или перед его компоновкой;
2) Auto dependencies — команда, позволяющая осу-
ществлять перетрансляцию файлов, входящих в проект,
в зависимости от даты их создания;
3) Clear project — команда удаления имени из пункта
Project name;
4) Remove messages—команда, осуществляющая
удаление сообщений об ошибках из окна сообщений.
Рассмотрим, как задаются режимы для отладки про-
граммы. Для этого используются пункты главного меню
Debug и Break/watch. В меню Debug есть следующие
режимы:
1) Evaluate — выводится окно для задания перемен-
ным, активизированным в пункте Break/watch, опреде-
ленных значений. В этом окне три раздела: Evaluate
(идентификатор анализируемой переменной или выраже-
ние с этой переменной), Rezult (результат вычисления
переменной или выражения на очередном шаге), New
value (здесь может быть введено новое значение, которое
будет присвоено выбранной в пункте Evaluate перемен-
ной). Аналогичные действия выполняются по команде
УПР — Ф4 (Ctrl — F4);
2) Call stack — отображается последовательность
вызова различных функций в языке СИ. На экране
появляется окно Call stack, и в нем можно проследить
вложенность функций. Так, при работе функции main
328
в окне будет только одно сообщение: main(). Если же
функция main вызывает функции fun, при выборе этого
режима в окне появятся два сообщения: fun() и ниже
main(). Аналогичные действия выполняются по команде
УПР — ФЗ (Ctrl — F3);
3) Find function — позволяет найти любую функцию
в текущей программе по ее имени, которое вписывается
в прямоугольник-подсказку (Enter subprogram symbol).
После нажатия клавиши ВВОД курсор переместит-
ся в строку с именем функции. Если указать несуществую-
щую функцию, появится сообщение: Symbol not fo-
und. Press ESC (имя не найдено, нажмите клавишу
КЛЮЧ);
4) Display swapping — задает режимы переключения
из окна редактора в окно пользователя для просмотра
результатов работы программы. В подрежиме Always
переключение происходит на каждом шаге отладки; в под-
режиме Smart — только в том случае, если в окне поль-
зователя изменяются результаты; в подрежиме None
предполагается, что результаты работы программы на
экран не выводятся;
5) Refresh display — используется для восстановления
информации на экране дисплея при случайном наложении
результатов работы программы на ее текст в окне ре-
дактора;
6) Souse debugging — позволяет включить (оп) ре-
жим отладки (с программами Turbo С debugger — отлад-
чик ТУРБО СИ и Turbo debugger — автономный ТУРБО
отладчик), включить режим отладки только с автономным
отладчиком (Standalone), выключить (None) режим от-
ладки.
Рассмотрим возможные режимы пункта Break/watch:
1) Add watch—позволяет включать переменные
в множество объектов, значения которых будут контроли-
роваться (здесь можно использовать не только перемен-
ные, но и выражения). Переменная, помеченная звездоч-
кой, является текущей (она всегда высвечивается на экра-
не, и с ней выполняются действия по умолчанию). Ана-
логичные действия выполняются по команде УПР—Ф7
(Ctrl — F7);
2) Delete watch —удаляет из списка контролируемых
объектов текущую переменную (помеченную звездочкой);
3) Edit watch — позволяет изменить текущую пере-
менную (выбрать новый объект, являющийся текущей
переменной);
329
4) Remove all watches — удаляет все переменные, зна-
чения которых контролируются при отладке;
5) Toggle breakpoint — задает контрольную точку
(при нажатии клавиши ВВОД она устанавливается там,
где расположен курсор). После ввода контрольных точек
выполнение программы (по команде УПР — Ф9) будет
осуществляться дискретно, т. е. до очередной контроль-
ной точки (после этого программу надо снова запускать
на выполнение путем нажатия клавиш УПР — Ф9). Ана-
логичные действия выполняются по команде УПР — Ф8
(Ctrl — F8);
6) Clear all breakpoints — исключает все контроль-
ные точки;
7) View next breakpoint— перемещает курсор к сле-
дующей контрольной точке (порядок перемещения кур-
сора соответствует последовательности выбора контроль-
ных точек в команде Toggle breakpoints).
9.6. ВЗАИМОДЕЙСТВИЕ ПРОГРАММ
Из программы, написанной на одном языке, можно
обращаться к программам, написанным на других языках.
Это позволяет наиболее эффективно использовать те
конструкции, которые необходимы пользователю.
Предположим, что программа на ПАСКАЛе cipas должна обра-
титься к подпрограмме fun на СИ. Вид этой подпрограммы на ПА-
СКАЛе— функция. Ей передаются значения двух переменных i и j
целого типа. Функция fun должна возвратить целое значение, равное
i — j, которое в ПАС КАЛЬ-программе выводится на экран. Текст
ПАС КАЛЬ-программы приведен ниже:
prcgrai cipas;
{$L c:prl«6.obj) ( подкмчение файда c:pri«.obj-.c
функцией fun }
var i, j:integer; [ обившие переиеинан i a j центе
„
function fun(i,j;integer);integer; external;
[ сбъкыеиие вненией функции (external)
fun c прогогипаии i и j. Функция fun
возвращает цехое значение }
begin
writelnf'Введите значений i н j через пробег);
read(i,j);
иг itelnifun(i,j)); { вывод на экран значения функции fun }
end
Объектный модуль функции fun, написанный на языке СИ, на-
ходится в файле c:prim6.obj, который подключается по директиве
($Lc; prim6.obj). Все остальное должно быть ясно из приведенных
содержательных комментариев.
330
Текст функции fun на языке СИ имеет следующий вид:
int fun(int b,int с)
(
int a;
a=b-c; /» вачнсаеше значение b-c (т.е. i-j) »/
return(a);/» возврадеаяе значение a=b-c. Здесь внес-
to двух операторов a:b-c; return(a);
«окно записать н одни: return!b-c); »/
}
Переменной i в программе на ПАСКАЛе соответствует b в программе
на СИ, а переменной j — с.
Выполним трансляцию исходного модуля rim6.c, например, с по-
мощью автономного компилятора ТСС.EXE (вместе с файлом ТСС.EXE
на том же диске должен находиться файл TURBOC.CFG, поставля-
емый с системой программирования ТУРБО СИ). Для этого в среде ОС
необходимо ввести следующую команду:
QTCC B:PR1M6,C<ВВОД>
В ней заданы вызываемый файл компилятора (ТСС) и спецификация
файла с исходным текстом программы (B:PRIM6.C). После выполнения
указанной команды модуль prim6.obj будет записан на диске С.
Дальнейшая работа идет с системой программирования ТУРБО
ПАСКАЛЬ (предположим, что соответствующий файл TURBO.EXE
находится на диске А). Сначала вводится команда
A)TURBO(BBOfl) •
Затем набирается текст ПАСКАЛЬ-программы (предположим, что со-
ответствующий файл имеет спецификацию b: pci.pas). Наконец, вы-
полняются компиляция, компоновка, загрузка и запуск программы pci
на выполнение. С клавиатуры вводятся два числа, например 10 и 6.
После этого на экране появится результат—4.
В следующем примере вид подпрограммы на ПАСКАЛе— про-
цедура. Исходные данные в нее вводятся с клавиатуры (а и Ь) и пере-
даются процедуре fun2 через глобальную область памяти (поэтому
у fun2 нет параметров). Затем в функции fun2, написанной на языке СИ,
значение а передается Ь, а значение b — а. Результаты тоже помещают-
ся в глобальную область, и поэтому они будут доступны в модуле
на ПАСКАЛе. Для выражения того факта, что переменные а и b
объявлены в программе на ПАСКАЛе, используется ключевое слово
extern. Соответствующие тексты приведены ниже:
prograa ttt; { нрограииа па язаке НЙСКАЛЬ )
№ c;pria9. ob j) { иодшченне файла c:pri»9.obj
с функцией funZ )
var a,b:integer;
procedure funZ; external;
{ объиилеиие яиевией процедуры futZ )
begin
»riteln('Введите значение a » b через пробег');
read(a,b); { яяод с наяиатура значений а и b }
«ritelnf'Иедодиае даииае: а : ',а,', b = ’,Ь);
funZ; { яазон ноднрограиин да saute С8 )
»riteln('Вогучеинай результат: а : '‘,а,’, b - ’,Ь);
end.
331
int fun2{void) /♦ fun2 иеивет места»! зшеш а и b */
( int с; /» объявление локальной каретной с»/
estern int a,b;
/» описание нереиении!, объявления'
я нрограиме на ПДСКАЛе </
с=а; а=Ь; Ь-с;
/» обвей значений нереиеииак а и b с исполь-
зоиаииеи протуточиой нереиенной с »/
}
Результаты работы программ представляются в следующем виде:
Введите значения а и b через пробел
27 48(ВВОД)
Исходные данные: а= 27, Ь=48
Полученный результат: а= 48, b = 27
Последние две программы иллюстрируют вызов из модуля на
ПАСКАЛе подпрограммы на СИ и затем вызов из нее подпрограммы
на ПАСКАЛе. Их тексты приведены ниже:
prograe vvv, { нрограииа на езыие ПАСКАЛЬ }
($1. c:priB10. obj} ( нодклсчеиие файла ciprielO.obj
с функцией fun.) }
var a,b,n: integer;
procedure fun3(n:integer); esternal;
{ объявление виеаией процедура fun.3 }
procedure sua(«:integer);
{ зга процедура будет вазаватьея нз
нрограиии на взаке СП }
begin
а::аП; Ь: = ЬЮ;
end; { конец процедура set. }
begin ( начало тела нрограиии }
Hriteln('Введите значения а, Ь, через пробел');
readla,b,п);
»riteln('Педодине даииме: а - b = ',Ь,',
п = ',п);
fun3(n); { вазон ноднрограиии на язаке СИ }
»riteln('Полученный результат: а: ',а,’, Ь: ’,Ь);
end. { конец тела нрограиии }
extern void sub(int n); /» процедура sub определена я
програиие на НЙСКйЛе >/
int fun3(int n)
( int c;
estern int a,b; /* описание переткни, объявленная
я програиие на НйСКАЛе »/
с-а; azb; b:c;
if(n!:0) suE(n); /» если значение п не равно иуп, то
вызов функции, определенной в програиие на ВйСШе »/ '
}
Процедура fun3 в модуле vvv — внешняя; она написана на СИ.
Из функции fun3 на СИ осуществляется обращение к внешней функции
sum, которая является процедурой, написанной на ПАСКАЛе (см. мо-
дуль vvv).Для упрощения восприятия материала действия в подпро-
граммах выбраны очень простые. Так, fun3 меняет местами значения
переменных а и b, a sum добавляет к каждому полученному значению
332
введенную с терминала величину п. Описание extern void sum (int i);
указывает на то, что функция sum не возвращает значений (void)
и является внешней (extern) Ей передается один параметр (п) целого
типа (int). Переменные а и b доступны основной ПАСКАЛЬ-программе
и всем подпрограммам, поскольку они помещены в глобальную область.
Результаты работы программы могут быть представлены, например,
в таком виде:
Введите значения а, Ь, п через пробел
4 9 О(ВВОД)
Исходные данные: а= 4, Ь=9. п=0
Полученный результат: а= 9, Ь=4
Здесь модуль sum не подключался, так как п= 0. Его вызов осущест-
вляется в следующем примере:
Введите значения a, b, п через пробел
4 9 10 (ВВОД)
Исходные данные: а= 4, Ь=9. п = 10
Полученный результат: а = 19. Ь= 14
10. БИБЛИОТЕКИ
10.1. ОБЩИЕ СВЕДЕНИЯ
Инструментальные системы программирования ТУРБО
СИ и ТУРБО ПАСКАЛЬ имеют обширные библиотеки,
содержащие подпрограммы для решения часто встречаю-
щихся задач. К их числу относятся вычисление математи-
ческих функций, ввод и вывод данных, обработка строк,
взаимодействие со средствами операционной системы
и т. п. Использование таких подпрограмм избавляет поль-
зователя от необходимости разработки соответствующих
средств и предоставляет ему дополнительный сервис.
Быстрое развитие систем программирования привело
к тому, что назначение большинства полезных библио-
течных функций в отечественной литературе практически
не рассмотрено. Настоящее справочное пособие в опре-
деленной мере компенсирует этот пробел. В нем рассмот-
рено большинство стандартных подпрограмм для совре-
менных систем программирования ТУРБО СИ (версия
2.0) и ТУРБО ПАСКАЛЬ (версия 5.0).
Стандартные функции языка СИ оформлены в соот-
ветствующие программные модули, включены в библиоте-
ки и поставляются вместе с системой программирования.
Их объявления даны в файлах *.h. Поэтому в начале
программы с библиотечными функциями должны появ-
ляться строки вида =D= include (включаемый файл типа Ь).
Стандартные функции языка СИ можно подразделить
на следующие группы:
1) математические функции (их объявления даны
в файлах math.h, float.h);
2) функции для проверки символов и их преобразо-
вания (их объявления даны в файле ctype.h);
3) функции ввода-вывода для стандартных файлов
(их объявления даны в файлах stdio.h, conio.h);
4) функции для работы с файлами (их объявления
даны в файлах stdio.h, io.h);
334
5) функции для работы со строками и фрагментами
памяти (их объявления даны в файлах stdlib.h, string.h
и mem.h);
6) функции для выделения и освобождения памяти
(их объявления даны в файле alloc.h);
7) функции для взаимодействия с операционной систе-
мой (их объявления даны в файлах dos.h, bios.h, time.h,
timeb.h, types.h, process.h);
8) функции для работы с каталогами (их объявления
даны в файле dir.h);
9) специальные функции (их объявления даны в фай-
лах stdarg.h, signal.h, setjmp.h, stat.h, assert.h, stdlib.h);
10) функции для работы с графикой (их объявления
даны в файле graphics.h);
11) функции для работы с окнами (их объявления
даны в файле conio.h).
Кроме того, существуют файлы типа h, в которых
заданы различные константы. Например, в файлах li-
mits. h, values.h с помощью команды препроцессора #de-
fine определены константы, характеризующие максималь-
ное и минимальное значения для различных типов данных.
В файле errno.h с помощью команды препроцессора
define определены различные виды ошибок, которые
могут возникать при программировании задач на язы-
ке СИ.
Функции из групп 10, 11 и из файла dos.h будут
описаны в гл. 11, 12.
В системе программирования ТУРБО СИ библиотеч-
ные функции находятся в специальных файлах. Так,
в файле MATH — .LIB находятся математические функ-
ции, EMU.LIB — функции для эмуляции чисел с плаваю-
щей запятой, С — .LIB—другие функции. Прочерк
в именах файлов (—) заменяет первую букву названия
используемой модели памяти.
В языке ПАСКАЛЬ существуют два способа органи-
зации подпрограмм: в виде процедур и в виде функций.
В отличие от процедуры функция обязательно возвращает
вычисленное значение в место своего вызова. Этим1 опре-
деляются различные способы обращения к стандартным
подпрограммам. Так, вызов процедуры всегда оформляет-
ся в программе как отдельный оператор и отделяется
точкой с запятой; обращение же к функции возможно
лишь в том месте программы, где допускается исполь-
зование значений соответствующего типа (в выражениях,
операторах присваивания и т. п.).
335
Описания и реализация стандартных процедур и функ-
ций помещены в библиотечный файл TURBO.TPL. В нем
также сделаны необходимые объявления констант, типов
данных и переменных. Для подключения к программе
того или иного раздела библиотеки используется оператор
USES разделы библиотеки (через запятую);
который записывается сразу после первой строки с за-
головком программы.
Можно выделить следующие группы стандартных
процедур и функций языка ПАСКАЛЬ:
1) математические процедуры и функции;
2) функции порядка и преобразования типов;
3) процедуры и функции для работы с файлами;
4) процедуры и функции для работы со строками
символов;
5) функции для работы с адресами и регистрами
микропроцессора;
6) процедуры и функции для работы с экраном
в текстовом режиме;
7) процедуры и функции для динамического распре-
деления памяти;
8) процедуры и функции для взаимодействия с опе-
рационной системой;
9) специальные процедуры и функции;
10) графические процедуры и функции.
Библиотека стандартных процедур и функций системы
программирования ТУРБО ПАСКАЛЬ реализована в фай-
ле TURBO.TPL и имеет модульную структуру. Она со-
держит семь основных модулей: SYSTEM, CRT, DOS,
PRINTER, GRAPH, GRAPH3, TURBO3.
Раздел библиотеки SYSTEM включает встроенные про-
цедуры и функции языка ПАСКАЛЬ, которые исполь-
зуются наиболее часто (подпрограммы для работы
с файлами, обработки строк символов, математические
функции и др.). Этот модуль подключается к любой
компилируемой программе без дополнительного объяв-
ления в строке USES. Обращение же к другим библио-
течным разделам требует обязательного указания компо-
новщику. Например, объявление USES CRT, CRAPH;
означает, что модули библиотеки CRT и GRAPH будут
подсоединены к программе и можно пользоваться всеми
сделанными в них определениями. В модуле DOS реали-
зованы процедуры и функции, позволяющие программе
на языке ПАСКАЛЬ взаимодействовать с операционной
336
системой MS-DOS. Здесь объявлены также требуемые
для этого переменные и типы данных. Модуль CRT содер-
жит набор определений, необходимых для работы с экра-
ном в текстовом режиме (создание экранных окон, прямое
управление курсором, установка цвета фона и символов,
подача звукового сигнала и др.). В разделе библиотеки
PRINTER объявляется файловая переменная LST, кото-
рой ставится в соответствие текстовой файл, используе-
мый для переадресации результатов работы программы
на принтер. В библиотечный раздел GRAPH включены
встроенные процедуры и функции для работы в графи-
ческом режиме и все необходимые для этого объявления.
Модуль GRAPH3 содержит графические подпрограммы,
которые были определены в системе ТУРБО ПАСКАЛЬ
версии 3.0. Раздел TURBO3 включает объявления пере-
менных и несколько процедур, которые использовались
ранее в версии 3.0, но не поддерживаются в новых вер-
сиях языка.
Кроме перечисленных выше, в библиотеку могут до-
бавляться новые разделы, созданные пользователем и
оформленные по определенным правилам. Такая органи-
зация библиотечного файла позволяет создавать компакт-
ные загрузочные модули, так как объектный код програм-
мы дополняется не всей библиотекой, а лишь необхо-
димыми для каждого случая ее разделами.
10.2. СТАНДАРТНЫЕ ФУНКЦИИ ЯЗЫКА СИ
10.2.1. МАТЕМАТИЧЕСКИЕ ФУНКЦИИ
Перечислим математические функции языка СИ. Сна-
чала приведем прототип функции, затем — необходимую
информацию об ее использовании:
int abs(int i) — возвращает абсолютное значение це-
лого аргумента i;
double acos(double x) — функция арккосинуса; значе-
ние аргумента должно лежать в диапазоне от —1 до 1;
double asin (double х) — функция арксинуса; значение
аргумента должно лежать в диапазоне от —1 до 1;
double atan (double х) — функция арктангенса;
double atan2 (double у, double х) — функция арктан-
генса у/х;
double cabs (struct complex znum) — вычисляет аб-
солютное значение комплексного числа; описание записи
типа complex дано в файле math.h;
337
double ceil (double x) — возвращает наименьшее це-
лое, большее или равное х;
double cos (double х) — функция косинуса; угол за-
дается в радианах;
double cosh (double х) — возвращает значение гипер-
болического косинуса х;
double exp (double х) — вычисляет значение ех (экспо-
ненциальная функция);
double tabs (double х) — возвращает абсолютное
значение вещественного аргумента х двойной точно-
сти;
double floor (double х) — возвращает наибольшее це-
лое, большее или равное х;
double fmod (double х, double у) — возвращает оста-
ток от деления х на у;
double frexp (double h, int *e) — возвращает значение
мантиссы и порядка *е; здесь х—мантисса (2*с);
double hypot (double х, double у) — возвращает
значение гипотенузы z правильного треугольника (z2 =
long labs (long x) — возвращает абсолютное значе-
ние длинного целого аргумента х;
double Idexp (double v, int e) — возвращает зна-
чение v2e;
double log (double x) — возвращает значение нату-
рального логарифма х (In х);
double loglO (double x) — возвращает значение
десятичного логарифма х (logiox);
double poly (double x, int n, double c []) — вычисляет
полином вида с [п] хп ф- с [п — 1 ] хп“ ф-... ф- с [1 ] хф-с [0];
double pow (double х, double у) — возвращает зна-
чение ху;
double powlO (int р) — возвращает значение 10р.
double sin- (double х) — функция синуса; „угол задает-
ся в радианах;
double sinh (double х) — возвращает значение гипер-
болического синуса;
double sqrt (double х) — возвращает значение д/хф
double tan (double х) — функция тангенса; угол за-
дается в радианах;
double tanh (double х) — возвращает значение гипер-
болического тангенса х.
Ниже приводится пример программы, демонстрирующий исполь-
зование математических функций:
338
linclude <stdio.b> /♦ пример исшьэовании »/
«include <aath.h> /» матешичесш функций »/
>ain()
( char str[]:"12345.6789"; double x,y;
,'i вычискение гнпотеиузн прикопанного треугольника
с катетами 3 и 4 »/
рг1пИ("\пгипотенуза равна; И\п",(int)hypotl3,4));
/« преобразование строки в число с пкававжей точкой «/
printf ("Полученное значение: П\п‘,atof(str) I;
/и получение ближайшего целого, больяего или равного
задаииону числу »/
printf("ЧислоД ; И; число-2 - td\n",(int)ceil( 1.398 ),
(int)ceilf675));
/» получение ближайшего целого, иеныего им равного
заданному числу »/
printfflHCio.l М; чисио.2 -- Jd\n",(int)floot( 1.398),
(int)floor(675)):
/« smciennr згачеин (x on паи У) */ r-256;
printfC'lf по модули If равио: W\n‘ ,x,y,feodfx,у));
/и возведение j в степень у •/ г2; у=16;
printf("Id в степени М равно: %ld\n",(int)j,(int)y,
(longJpow(i,y));
/t возведение 10 в степень у */ у;3;
printf("Десять в степени И равно: М\п",(intly,
(intJpowlO((inijy1);
/» внчисленне значении корня из j »/ к=700-,
printf("Корень из If равен: %lf\n",х,sqrt(x)l; )
Текст программы снабжен содержательными комментариями,
не требующими дополнительных пояснений. Результаты ее работы
представляются в следующем виде:
гипотенуза равна: 5
Полученное значение: 12345.678900
ЧИС1О.1 - 2; чисю_2 ; 675
ЧИС1О.1 - 1; число.? - 675
400.000000 по модули 256.000000 равно: 144.000000
2 в степени 16 равно: 65536
Десять а степени 3 равно: ЮОО
Корень из 700.000000 равен: 26.457513
10.2.2. Функции для проверки символов
и их преобразования
Перечислим функции для проверки символов и их пре-
образования:
int isalnum(int с) — дает значение не нуль, если С —
буква или цифра (А — Z, а — z, О—9), и нуль — в про-
тивном случае;
int isalnum (int с) — дает значение не нуль, если с —
буква (А—Z, а — z), и нуль—в противном случае;
int isascii(int с) — дает значение не нуль, если с лежит
в интервале от О до 127, и нуль— в противном случае;
int iscntrl(int с) —дает значение не нуль, если с —
управляющий символ (0x7F или ОхОО—Oxi F), и нуль —
в противном случае;
339
int digit(int c) — дает значение не нуль, если с — циф-
ра (0—9), и нуль— в противном случае;
int isgraph(int с) —дает значение не нуль, если с —
видимый символ (0x21—0x7F), и нуль — в противном
случае;
int islower(int с) —дает значение не нуль, если с —
на нижнем регистре (а—z), и нуль — в противном слу-
чае;
int isprint(int с) —дает значение не нуль, если с —
печатный символ (0x20—0x7F), и нуль—в противном
случае;
int ispunct(int с) — дает значение не нуль, если с соот-
ветствует iscntrl или isspace, и нуль — в противном случае;
int isspace(int с) —дает значение не нуль, если с —
пробел, символ новой строки, возврата каретки (0x09—
0x0D, 0x20), и нуль— в противном случае;
int isupper (int с) —дает значение не нуль, если с —
на верхнем регистре (А — Z), и нуль — в противном
случае;
int isxdigit(int с) —дает значение не нуль, если с —
шестнадцатеричное число (0—9, А — F, а — f), и нуль —
в противном случае;
int toascii(int с) — преобразует целое число в символ
ASCII-кода;
int__tolower(int с) — преобразует с к нижнему регист-
ру (работает только для букв латинского алфавита);
int__toupper(int с) — преобразует с к верхнему ре-
гистру (работает только для букв латинского алфавита).
Последние две функции могут быть использованы и без
первого символа подчеркивания.
10.2.3. Функции ввода-вывода
для стандартных файлов
Перечислим функции ввода-вывода для ^стандартных
файлов:
int getch(void) — считывает один символ с пультового
терминала без отображения на экране дисплея;
int getchar(void) — считывает символ из стандартного
потока ввода (с клавиатуры);-
char*gets (char*str) — считывает строку str из стан-
дартного потока ввода (с клавиатуры);
int printf(const char *format,...) —функция форма-
тированного вывода; подробно описана в гл. 6;
int putchar(int с) — записывает символ с в стандарт-
ный поток вывода (на экран дисплея);
340
int puts (char *str) —записывает строку str в стан-
дартный поток вывода (на экран дисплея);
int scant (const char ^format,...) —функция формати-
рованного ввода; подробно описана в гл. 6;
int sprintf (char *str, const char *format,...) — функция
форматированной записи в строку str; подобна функции
printf, но вывод осуществляется не в стандартный поток,
а в строку str;
int sscanf(const char *str, const char *format,...) —
функция форматированного чтения из строки str; подобна
функции scant, но ввод осуществляется не из стандартного
потока, а из строки str;
int ungetc(int с, FILE *fp) —возвращает символ с
в файл с логическим именем fp;
int ungetch(int с) — возвращает символ с в стандарт-
ный поток ввода, заставляя его быть следующим счи-
танным символом;
int vprintf (const char *format, va_list arg) — функ-
ция форматированного вывода в стандартный выходной
поток (на экран дисплея) значений аргументов из списка
arg типа va__list (такой тип определен в файле stdarg.h);
предназначена для работы с va-функциями, обеспечиваю-
щими задание подпрограмм с переменным числом пара-
метров;
int vscanf (const char *format, va__list arg) —функ-
ция форматированного ввода из стандартного входного
потока (с клавиатуры) значений аргументов из списка
arg типа va__list; предназначена для работы с va-функ-
циями;
int vsprintf (char*str, const char ^format, va_______list
arg) — подобна функции vprintf, но вывод осуществляется
не в стандартный поток, а в строку str;
int vsscanf (const char *str, const char ^format, va_list
arg) — подобна функции vscanf, но ввод осуществляется
не из стандартного потока, а из строки str.
10.2.4. Функции для работы с файлами
Перечислим функции для работы с файлами:
int access (const char *f, int n) — проверяет файл,
заданный строкой f; тип проверки задается значением
переменной п (0 — проверка на существование, 1 —
на выполняемость, 2 — на запись, 4 — на чтение, 6 — на
запись и чтение) при успешном завершении возвра-
щает 0;
341
void clearerr(FILE *f) —обнуляет признак ошибки
файла f;
int___chmod(const char *p, int fun,...) —определяет
либо изменяет атрибуты файла, заданного строкой р.
Если fun = 0, __chmod возвращает значение атрибута
файла; если fun=l, она устанавливает эти атрибуты.
Сами атрибуты перечисляются в списке (многоточие)
в виде соответствующих целых чисел. В случае ошибки
возвращает значение —1;
int chmod (const char *p, int mode) — изменяет
атрибуты файла (mode), заданного строкой р, при
успешном завершении возвращает 0, в противном слу-
чае — 1;
int __close(int h) или int close (int h) — прекращает
действие заданного номера h файла; при успешном
завершении возвращает 0, в противном случае —1;
int __creat(const char *p,int attr) — создает новый
файл, заданный строкой р с атрибутами attr; при успеш-
ном завершении возвращает номер (handle) этого файла,
в противном случае —1;
int creat(const char *p,int mode) — подобна функции
__creat;
int creatnew (const char *p, int mode) — создает новый
файл, заданный строкой р с атрибутами mode; отличается
от___creat только тем, что в случае, если подобный файл
уже существует, будет возвращена ошибка (— 1);
int dup(int h) — при успешном завершении возвра-
щает дублирующий номер для файла с существующим
номером h; при ошибке возвращает значение —1;
int eof (int h) — проверяет наличие конца файла с но-
мером h; возвращает значения: 1 — в случае конца файла;
О — в случае отсутствия конца файла, —1 — при наличии
ошибки;
int fclose(FILE *f) —закрывает файл F;
int fcloseall (void) —закрывает все открытые файлы;
int feof(FILE *f) —возвращает ненулевое значение
при правильной записи в файле f признака конца файла;
int terror (FILE *f) — возвращает ненулевое значение,
если в файле f обнаружена ошибка;
int fflush(FILE *f) — записывает символы из буфера
в файл f;
int fgetc(FILE *f) — получает очередной символ из
файла f;
int fgetpos(FILE *f, long *poz) — позволяет получить
значение *poz указателя текущей позиции в файле f; при
342
успешном завершении возвращает нуль, в противном слу-
чае — не нуль;
char *fgets(char *s,int п, FILE *f) — позволяет полу-
чить строку s из файла f длиной п; возвращает значение
NULL при ошибке;
long filelength (int h) — возвращает длину (в байтах)
файла, связанного с номером h; в случае ошибки возвра-
щает значение —1;
int fileno(FILE *f) — возвращает значение номера h
для файла f;
FILE *fopen (const char *f, const char *t) — открывает
файл, который задает строка f (f указывает на специфи-
кацию либо маршрут к файлу); строка t имеет одно из
следующих значений: ”г” — открытие файла f только для
чтения; ”w” — открытие файла f только для записи; ”а” —
открытие файла f для дополнения, ”г + ” — открытие су-
ществующего файла для изменения, ”w+” — создание но-
вого файла для изменения, ”а + ” — открытие для измене-
ния в конце файла. Если файл открыт или создан, к значе-
нию t в виде текста добавляется буква t (например,
”wt”, ’’r-f-t” и т. п.); если файл задан в двоичной форме,
добавляется b (например, ”wb”, ”а-|-Ь” и т. п.); при ус-
пешном завершении функции возвращается значение
NULL;
int fprintf (FILE *f, const char *format,...) —функция
форматированного вывода в файл f; подобна функции
printf;
int fputc(int c, FILE *f) — выводит символ с в файл f;
int fputs(const char *s, FILE *f) — записывает строку
s в файл f;
unsigned fread [void *obl, unsigned dl, unsigned
nb, FILE *f) — читает из файла f в блок (область)
obi nb элементов данных, каждый длиной dl байт; при
успешном завершении возвращает число элементов дан-
ных;
FILE *freopen (const char *f, const char *t, FILE
*fn) — закрывает и открывает заново файл fn со специфи-
кацией f; возможные значения строки t перечислены для
функции fopen; при успешном завершении возвращает
значение NULL;
int fscanf (FILE *f, const char*format,...) —функция
форматированного вывода из файла f; подобна функции
scanf;
int fseek (FILE *f, long poz, int s) — перемещает ука-
затель текущей позиции в файле f в позицию pos, которая
343
отсчитывается от начала файла при s=0; от текущей
позиции при s= 1; от конца файла при s = 2;
int fsetpos (FILE*f, const long*poz)—устанавливает
указатель текущей позиции в файле f в соответствии со
значением *poz;
long ftell (FILE *f) —возвращает значение указателя
текущей позиции в файле f;
unsigned fwrite(const void *obl, unsigned dl, unsigned
nb, FILE*f) — записывает в файл f из блока (области)
obi nb элементов данных, каждый длиной dl байт; при
завершении возвращает число элементов данных;
int getc(FILE *f) — считывает символ из файла f;
int getftime(int h, struct ftime *ft) — позволяет полу-
чить в виде значений элементов записи *ft время и дату
создания файла с номером h; запись типа ftime определена
в файле io.h;
int getw(FILE *f) — возвращает целое число, получен-
ное из файла f;
long Iseek (int h, long poz, int s) — перемещает
указатель текущей позиции в файле с номером h; аналогич-
на функции fseek;
int puts (int c, FILE *f) —записывает символ с в
файл f;
int__read (int h, void *buf, unsigned len) — считывает
len байт из файла с номером h в буфер buf; при ошибке
возвращает значение —1;
int read (int h, void *buf, unsigned len) — подобна
функции__read;
int rename (const char *old, const char *new) — изменя-
ет имя файла от old к new; при успешном завершении
возвращает нуль;
void rewind (FILE *f) —перемещает указатель теку-
щей позиции в начало файла f;
int setftime (int h, struct ftime *ft) — позволяет устано-
вить время и дату создания файла с номером h в виде
элементов записи *ft типа ftime;
int setmode (int h, int mode) — устанавливает атрибуты
mode открытого файла с номером h;
long tell (int h) — возвращает значение указателя
текущей позиции для файла с номером h;
int ungetc(char с, FILE *f) — возвращает символ с в
файл f;
int unlink (const char *f) —удаляет файл, заданный
строкой f; возвращает нуль при успешном завершении
и —I при ошибке;
344
int vfprintf (FILE *f, const char *format, va_list arg) —
функция форматированного вывода в файл f значений
аргументов из списка arg типа va_list; предназначена для
работы с va-функциями;
int vfscanf (FILE *f, const char *format, va__list arg) —
функция форматированного ввода из файла f значений
аргументов из списка arg типа va_list; предназначена для
работы с va-функциями;
int_write(int h, void *buf, unsigned len) — записывает
len байт из буфера buf в файл с номером h; при ошибке
возвращает значение —1;
int write (int h, void *buf, unsigned len) — подобна
функции write.
Приведем пример программы, демонстрирующей использование
некоторых функций для работы с файлами:
linclude <io.h> ярямер ясяодьзоваияя функций
Ifinclude <sUlo.h> /I ди рабой с файдаия »/
aln()
( int i.nl;
HIE Ир;
fp=fopen('iet81.c","r');
/к яроверка иа судесдвоваияе файда де181.с в декудем
ддрекдорид (с воэмощиосдьв эаисд к чдеидя) И
i=access("ае181.с“,6);
puts)"Файд aeiSl.c судесдвуед");
else ри1з('Файд aeiBl.c не судесдвуед');
/< создание в декудем директория файда newf.с с атрибутом О I/
creat("ней!.с',0);
printf('Нойер файда fp: %d\n',(i=filenoffp),i));
ni=dup(i); /» создание дубируддего номера файда fp »/
printf('80HH8 нонер файда fp: id\n",ni);
printfi'PasHep файда fp в байдад: Hld\n",filelengtli(ni));
printf('Текудая доэдцда указадедя: Ud\n‘,tell(ni));
lseek(i,155,0); /» од иачада файда »/
printf('Текудая доэдцдя укаэадедя: Ud\n",tell(ni));
lseek(i,-)0,l); /» од декудей позиции »/
printf('Текудая доэдцин указадедя: Xld\n‘,tell(ni));
lseek(i,-)55,2); /» од конца файда </
printf('Текудая позмция указадедя; Hld\n",tell(ni));
fclose(fp); )
Результаты работы программы представляются в следующем виде:
Файд aetBl.c судесдвуед
Номер файда fp: 5
Новнй номер файда fp: 6
Размер файда fp в байдая; 1161
Текущая доэиция указадедя: 0
Текущая яоэдция указадедя: 155
Текущая доэицдя указадедя: 145
Текудая доэиция указадедя: 1006
345
10.2.5. Функции для работы со строками
и сегментами памяти
Перечислим функции для работы со строками и сег-
ментами памяти:
double atof(char *str) — преобразует строку str в ве-
щественное число двойной точности;
int atoi(char *str) — преобразует строку str в десятич-
ное целое;
long atol (char *str) — преобразует строку str в длин-
ное десятичное целое;
char *ecvt (double v, int n, int *d, int *sn) — преобра-
зует число с плавающей точкой в строку (здесь v — задан-
ное число; п — количество цифр в строке; d — указатель
на позицию десятичной точки; sn —указатель на знак);
возвращает указатель на полученную строку;
char *fcvt(double v, int n, int *d, int *sn) —подобна
функции ecvt;
char *gcvt (double v, int n, char *buf) —пре-
образует число v с плавающей точкой в строку из п
цифр (здесь but — указатель на эту строку); возвращает
указатель на полученную строку;
char *itoa(int v, char *str, int baz) —преобразует
целое v в строку str для системы счисления с основанием
baz (2с; baz 36);
char *ltoa(long v, char *str, int baz) —преобразует
длинное целое v в строку str по аналогии с функцией itoa;
void *memccpy (void *pm, const void *st, int ct, unsigned
n) — копирует блок памяти, на который указывает ist, в
блок, на который указывает pm, до тех пор, пока не встре-
тится первая цифра ct (размер копируемого блока — п
байт);
void *memchr(const void *s, int ch, unsigned n) —
возвращает указатель на первый встретившийся символ ch
в блоке s длиной п байт; если такого символа,цет, возвра-
щается NULL;
int memcmp (const void *pm, const void *ist, unsigned
n) — сравнивает две области памяти, на которые указы-
вают pm и ist (длина областей — п байт); возвращает
значение меньше нуля, если pm(ist; равное нулю, если
pm=ist, и больше нуля, если pm)ist. В приведенных
операциях отношения (( =,)) предполагается сопостав-
ление содержимого соответствующих областей памяти;
void *memcpy(void *pm, const void *ist, unsigned n) —
копирует блок длиной п байт из области памяти, на кото-
рую указывает ist, в область, на которую указывает pm;
346
int memicmp (const void *pm, const void *ist, unsigned
n) — подобна memcmp, за исключением того,'что игнори-
руются различия между буквами верхнего и нижнего ре-
гистров;
void *memmove(int *pm, const void *ist, unsigned
n) — копирует блок длиной n байт из области, на кото-
рую указывает ist, в область, на которую указыва-
ет pm;
void *memset void *pm, int ct, unsigned n) — назначает
первым п байтам блока памяти, на который указывает
pm, значение ct;
void movedata (unsigned istseg, unsigned istoff, unsig-
ned pmseg, unsigned pmoff, unsigned n) — копирует n
байт из области памяти istseg:istoff в область pmseg:pmoff
(здесь istseg и istoff — сегментный адрес и смещение
начального байта источника данных; pmseg и pmoff —
сегментный адрес и смещение начального байта приемника
данных);
void movmem (void *ist, void *pm, unsigned n) —
перемещает блок длиной п байт из области, на которую
указывает ist, в область, на которую указывает pm;
void setmem (void *pm, unsigned n, char ct) — записы-
вает значение ct в n байт области памяти, на которую
указывает pm;
char *stpcpy (char *pm, const char *ist) — копирует
строку, на которую указывает ist, в строку, на которую
указывает pm; возвращает указатель на pm-|-strlen (ist),
т. е. на pm плюс длина строки ist;
char *strcat(char *pm, const char *ist) — приписывает
строку, на которую указывает ist, к строке, на которую
указывает pm;
char *strchr (const char *ist, int ct) — нахо-
дит в строке, на которую указывает ist, первое вхождение
ct;
int strcmp (const char *strl, const char *str2) — сравни-
вает строки strl и str2. Результат отрицателен, если
strl <str2; равен нулю, если str l = str2; положителен, если
strl >str2;
char *strcpy (char *pm, const char *ist) — копирует
строку, на которую указывает ist, в строку, на которую
указывает pm; возвращает указатель на pm;
unsigned strcspn(const char *strl, const char str2) —
определяет длину первого сегмента строки strl, содержа-
щего символы, не входящие в множество символов str2;
char *strdup (const char s) — возвращает указатель
347
на строку, повторяющую (дублирующую) s; если недоста-
гочно памяти, возвращается NULL;
char *strerror(int n) — возвращает указатель на стро-
ку, содержащую сообщение об ошибке с номером п;
int stricmp(const char strl, const char str2) —сравни-
вает строки strl и str2, игнорируя различия между
строчными и прописными буквами (аналогична функции
strcmp);
unsigned strlen(const char *str) — вычисляет длину
строки str (в байтах);
char strlwr(char *str) — преобразует буквы верхнего
регистра в строке к буквам нижнего регистра;
char *strncat (char *pm, const char *ist, unsigned m) —
приписывает m символов строки, на которую указывает
ist, к строке, на которую указывает pm;
int strncmp (const char *strl, const char *str2, unsigned
m) — сравнивает строки strl и str2, причем рассматри-
ваются только первые m символов; результат аналогичен
strcmp;
char *strncpy (char *pm, const char *ist, unsigned m) —
копирует m символов строки, на которую указывает ist,
в строку, на которую указывает pm;
int strnicmp (const char *strl, const char str2,
unsigned m) — подобна функции strncmp, но игнорируют-
ся различия между строчными и прописными буквами;
char *strnset(shar *str, int ct, unsigned n) — запи-
сывает символ ct в первые n байт строки str; прекращает
работу, когда записаны п символов либо встретился
признак конца строки str; возвращает указатель на str;
char *strpbrk(const char *strl, const char *str2) — на-
ходит в строке strl первое появление любого из множе-
ства символов строки str2;
char *strrchr (const char *str, int ct) — находит в строке
str последнее вхождение символа ct;
char *strrev(char *str) —поворачивает относительно
центра все символы в строке str, исключая заключитель-
ный нуль; возвращает указатель на начало повернутой
строки;
char *strset(char *str, inc ct) —записывает ct во все
байты строки str; возвращает указатель на str;
unsigned strspn(const char *strl, const char *str2) —
определяет длину первого сегмента строки strl, содержа-
щего символы из множества символов, входящих в строку
str2;
char *strstr(const char *strl, const char *str2) —
348
находит первое появление подстроки str2 в строке strl;
возвращает указатель на первый элемент str2 в строке
strl либо NULL, если str2 не содержится в strl;
double strtod (const char *str, char **p) — преобразует
строку str в число с плавающей точкой двойной точности.
Если **р — не NULL, то *р указывает на последний преоб-
разованный символ строки str, которая должна иметь вид
[w] [S] [d] [.] [d] [f[s]d], где [w] — необязательный
пробел; [s] — необязательный знак (+ или —); [d] — не-
обязательные цифры; [f] — необязательный символ е или
Е; [.] — необязательная десятичная точка. Функция
strtod прекращает чтение строки при обнаружении недо-
пустимого символа; она возвращает полученное значение
типа double;
char *strtok (char *strl, const char *str2) — просмат-
ривает строку strl до первого появления символа, не
содержащегося в str2. Если такой знак найден, в следую-
щий после него байт записывается ’\0’ и возвращается
указатель на найденный знак; в противном случае возвра-
щается NULL;
long strtol (const char *str, char **p, int baz) — пре-
образует строку str в длинное целое в системе счисления
с основанием baz (2^baz^C36). Строка str должна иметь
вид [w] [s] [0] [х] [d], где [0] —необязательный
нуль; [х] — необязательный х или X; остальные символы
интерпретируются так же, как в strtod. Чтение строки
останавливается при первом недопустимом символе (на
него будет указывать *р). Функция возвращает получен-
ное значение типа long;
unsigned long strtoul (const char *str, char **p, int
baz) — преобразует строку str в беззнаковое длинное це-
лое; подобна функции strtol;
shar *strupr (char *str) — преобразует буквы нижнего
регистра в строке str к буквам верхнего регистра;
void swab (char *from, char *to, int n) —копирует, n
байт из строки from в строку to с перестановкой смежных
битов четных и нечетных байтов (вращает их на 180 гра-
дусов относительно центра); это полезно для пересылки
данных с одной машины на другую с различным располо-
жением байтов в числе;
char *ultoa (unsigned long v, char *str, int baz) — пре-
образует беззнаковое длинное целое v в строку str (см.
также itoa).
Ниже приводится пример программы, демонстрирующей использо-
вание некоторых функций для работы со строками;
349
iinclufe (string.h> /» пример ^пользования фуияццй »/
^include <stdio.h> /» ди работы со строками »/
»ain()
( char str[ 1 -- "ИРП 25 дет';
char s[) - "Кафедра ЭВМ";
char sn[50J; int k; puts(str); puts(s);
/» i строке s находится последнее яхохдение синода 'а' »/
*strrchr(s,"а"} : 'е'; /» 'а' заменяется на е' »/
strcpyfsn,s); /» строка з копируется н строку so »/
/» вндеяеиие н строке str верного пробела; приписыяание
посдедуядей части строки str к строке so »/
strcatlsn,strchrlstr, '));
pots(sn); /» будет яняедеиа строка 'Кафедре ЭВМ 25 дет' »/
/» сраянеиие строк sn и str (функция strcap) »/
printf("Результат сраянення: %d\n",strcip(sn,str));
/» начисление длина строки sn (функция strlen) »/
printf("Ддина стром sn: Xd\n",strlen(sn});
/» наделение я строку sn дня снияодоя, перяай нз которых
'2'; паление остшейся части строки sn (sn[2J:NUll) »/
strncpy(sn,strchr(str,'2'),2); sn[2]=NULL; putslsn);
k - atoi(sn); /» преобразование строки н целое число »
printf("десятичное число: Xd\n",к);
/» преобразояаиие целого н строку (число дяоичиое) »/
printf("дяоичиое число: Js\n',itoa(k,s,2));
/» формат преобразояаиия - четириадцатеричиое число »/
printf(’четыриадцатеричное число: ks\n',itoa(k,s,14));
getchO; }
Результаты работы этой программы представляются в следующем
виде:
МРТВ 25 лет
Кафедра ЭВМ
Кафедре ЭВМ 25 дет
Результат сраяиеияя-. -2
Длина строки sn: 18
25
десятичное число: 25
дяоичиое число; 11001
четариадцатеричиое число: lh
10.2.6. Функции для выделения
и освобождения памяти
Перечислим функции для выделения и освобождения
памяти: 1
int brk(void *addr) —устанавливает наибольший ад-
рес addr для сегмента данных; при успешном завершении
возвращает значение нуль, в противном случае —1;
void *calloc(unsigned n, unsigned m) — возвращает
указатель на начало выделенной области оперативной па-
мяти для размещения п элементов по m байт каждый; при
неудачном завершении возвращается значение NULL;
unsigned coreleft (void) —для моделей памяти tiny,
small, medium; unsigned long coreleft (void) —для других
моделей памяти; возвращает значение объема неиспользо-
350
ванной памяти (для модели small, установленной по умол-
чанию, возвращается объем неиспользуемой памяти в сег-
менте данных);
void free(void *bl) —освобождает ранее выделенный
блок оперативной памяти с адресом первого байта Ы;
void *malloc (unsigned s) —возвращает указатель
на выделенный блок оперативной памяти длиной s
байт; при неудачном завершении возвращает значение
NULL;
void *realloc(void *bl, unsigned ns) —изменяет раз-
мер ранее выделенной оперативной памяти с адресом нача-
ла Ы на ns байт; при неудачном завершении возвращает
значение NULL;
void *sbrk(int incr) — изменяет пространство для сег-
мента данных, добавляя к нему incr байт; при ошибке
возвращает значение —1;
void far *farcalloc(unsigned long n, unsigned long
m) — возвращает указатель на начало выделенной обла-
сти оперативной памяти для размещения п элементов
по m байт каждый; при неудачном завершении возвра-
щает значение NULL. В отличие от функции calloc поз-
воляет работать с памятью размером больше одного сег-
мента;
unsigned long farcoreleft(void) — возвращает значе-
ние объема неиспользованной памяти. В отличие от функ-
ции coreleft позволяет работать с памятью размером
больше одного сегмента;
void farfree(void far *bl) —освобождает ранее выде-
ленный блок оперативной памяти с адресом первого байта
Ы; предназначена для работы с функциями farcalloc,
farmalloc;
void far *farmalloc(unsigned long nb) — возвращает
указатель на выделенный блок оперативной памяти длиной
nb байт. В отличие от функции malloc позволяет работать
с памятью размером более одного сегмента;
void far *farrealloc(void far *oldbl, unsigned long
nb) — изменяет размер ранее выделенной оперативной па-
мяти с адресом начала oldbl на nb байт; при неудачном
завершении возвращает значение NULL. В отличие от
функции realloc позволяет работать с памятью размером
больше одного сегмента.
Ниже приводится пример программы, демонстрирующей использо-
вание некоторых функция для выделения и освобождения оперативной
памяти. Здесь же показано применение функций для работы с сегмен-
тами памяти (см. п. 10 2 5)
351
«include (alloc.h> /> иркмер ясиоаъзонаиия фуикцяй для >/
^include <stdio.li> /» яндеяеняя i осяобоцеии! памяти, ♦/
(include <aei.h> /» а таш для работы с сегиеитаии »/
iain() /л паиятя ♦/
{ unsigned long kol=80000,i,j=0; int as=O,sc-O;
unsigned char far »p; /» i случае иеобходяирстя иор-
иадизацяя результата иеобюдиио объявлять luge »р;
например; unsigned char huge »р »/
char »p»,»ist,»pc; /» обыненяе указателей »/
printf)"\п\п\пОбъеи иеясподьзуеиой паиятя я сегменте"
" даиинх; Xu\n",coreleft(l);
iftlpa : calloc(20,500)) - NOLL) ( putsf«aio паиятя"J;
abort!I;) /> динаияческое яадедеиие памяти объемом
10000 байт (500 блома по 20 байт) »/
printf(’Объем иеясподьзуемой памяти в сегменте дайнах:"
" Xu (node яазояа саHoc)\n”,coreleft());
free(pi); /1 освободдемне выделенной памяти «/
printf("Объем иеисподьзуемой памяти и сегменте данных:*
' in (после яазояа free)\n",coreleft());
ist=nalloc( 1000 ); ptcialloci 1000 ); pc=nalloc( 1000 );
for(1-0;i<1000;iet) »(ist»i)’-iX7;
/» копирояаиие блоха памяти, на который указаяает 1st, а
блок, иа который указыяает pi »/
еисру (pm, 1st, ЮОО);
/» аналогичное предадудему случаи копирование блока до
тех нор, -пока не ястрегнтся перяая цифра 5 •/
вевссру(₽с,1st,5,1000);
for(1=0;i<1000;i+t) ( ss к »рин; sc ♦: »pctt; )
pa-:1000; pc--1000; /» устаиояка иа начало блокоя »/
printffсумма значений элементен: ss = Xd; sc = Xd\n"
,ss,sc);
/* Функция эеэсар произяодит сравнение двух блоков памяти »/
printf("результат сравнения; Jd(p« и istI %d(pn и рс)'
"\n",memcnp(pa,ist,100),meacap(pc,pa,1000));
/> перяыи 100 элементам блока памяти, иа который
указывает рм, назначается значение 5 »/
nenset (ра, 5,100)-, ss=0;
for( 1=0;i< 100;io) ss+=»pmt+; pa-=100;
printf("иояая сумма: %d\n",ss);
printf("O6ieM неиспользуемой памяти; Xld\n”,
farcoreleft(l);
/» динамическое выделение памяти объемом 80000 байт V
Р - faraalloc(kol); if(p;:HDLL) eiitf);
/» если pcNDLL, заяермение работа программы »/
printf("Объем неиспользуемой памяти: Xld (после яызо
"на faraaHoc)\n",farcoreleftt)I;
/» занесение ио ясе четиае байта 1, а а нечетные 7 »/
for(i=l;icBOOOO;Н1 if(iX2) »рн = 1; else »₽н = 5;
/» суммирование яеек чисел я наделениям 80000 байтах »/
for(i=l;i<=80000;i‘t) j+=*—р;
printf("cyMMa чисел: Xldin’J);
/» праяидьиай результат 2(0000 »/
farfree(p); /» освобождение 80000 байт памяти »/
printf(“Объем неиспользуемой памяти; Xld (после яазо"
"на farfree)\n“,farcoreleft());
getchl), /» необходимо нахать лнбув клаянму »/ )
352
Результаты работы этой программы представляются в следующем
виде;
Объем ие«спо1ьзуеиой памяти i сегменте данных; 63412
Объем неиспохьзуеиой памятв i сегменте даиинх: 53434 (после внпова calloc
Объем иеисподьпуеиой паинтн i сегменте данных; 63412 (иосде яыпояа free}
сукна значений эдемеятон; ss - 2337; sc - 15
результат сранеим; 0(рк и 1st} -6(рк к рс}
нояая сумма: 500
Объем невсзодьзуемой памятн; 432236
Объем неиспользуемой памяти: 412280 (после вызова farialloc}
сумма чисел: 240000
Объел неиспользуемой памяти: 432236 (после шзока farfree}
10.2.7. Функции для взаимодействия
с операционной системой
Перечислим функции для взаимодействия с ОС (здесь
мы не рассматриваем функции файла dos.h, которые будут
описаны в гл. 12):
void abort (void) — аварийно завершает процесс;
char * asctime(const struct tm * tbl) — преобразу-
ет дату и время в ASCII-строку; возвращает указа-
тель на эту строку. Запись типа tm определена в файле
time.h;
int bioscom(int cm, char b,int port) —функция для
работы с коммуникационным адаптером RS-232C. Пере-
менная ст имеет следующие значения: 0 — для установки
параметров связи к значению b, 1 — для передачи байта,
2 — для приема байта, 3 — для возврата текущего состоя-
ния порта. Переменная port равна нулю для адаптера
СОМ1 и единице для адаптера COM2;
int bioskey(int cm) — функция для работы с клавиа-
турой. Если ст=0, возвращается скэн-код из буфера, ко-
торый при этом очищается; если буфер пуст, ожидается
нажатие клавиши; при cm= 1 всзвращается скэн-код из
буфера, но буфер не очищается; если буфер пуст, воз-
вращается нуль; при ст = 2 возвращается состояние
модифицирующих клавиш;
int biosmemory(void) — возвращает объем оператив-
ной памяти в килобайтах;
long biostime(int cm,long int) — функция для работы
с таймером. Если ст=0, происходит чтение состояния
таймера; при cm= 1 осуществляется установка таймера.
Время отсчитывается от полночи в единицах: 1/18,2 с;
long clock (void) — возвращает число импульсов дли-
тельностью 1/18,2 с, отсчитанных от начала работы
программы;
char *ctime (const long * t) — преобразует дату и вре-
12 Скляров В. А.
353
мя в строку; возвращает указатель на эту строку (здесь
*t — время в секундах, отсчитанное от 00 часов 00 минут
00 секунд 1 января 1970 г.);
double difftime(long t2,long tl) — возвращает разницу
во времени (в секундах) от tl к t2;
exec...— группа функций, которые загружают и выпол-
няют другие программы:
int execl (char * р, char * argO,...);
int execle(char * p, char * argO,...);
int execlp(char * p, char * argO,...);
int execlpe(char * p, char * argO,...);
int execv(char * p, char * argv [ ] );
int execve(char*p, char* argv [ ], char**env);
int execvp (char * p, char * argv [ ] );
int execvpe(char * p, char* argv [ ], char**env).
Функции семейства exec загружают и выполняют
другие программы, составляющие подчиненный (дочер-
ний) процесс. Если вызов ехес успешен, дочерний про-
цесс перекрывает родительский процесс. При этом должно
быть достаточно памяти для загрузки и выполнения
дочернего процесса. Переменная р указывает на имя фай-
ла вызванного дочернего процесса, дополненного именем
диска или маршрутом. Суффиксы 1, v, р и е, добавленные
к имени ехес, модифицируют функцию следующим об-
разом: р— функция будет искать файл в тех каталогах,
которые определены с помощью команды PATH опера-
ционной системы; в противном случае функция анали-
зирует только корневой и текущий каталоги; 1 — указа-
тели argO, argl,... переводятся как раздельные аргументы
(используется, если число аргументов заранее известно);
v — указатели arg [0], arg [ 1],... переводятся как массив
(используется, если число аргументов переменно); е—
аргумент env (новое окружение операционной системы)
может быть переведен в дочерний процесс (без суффикса
е дочерние процессы наследуют операционную среду роди-
тельского процесса). Каждая функция в семействе ехес
должна иметь один из двух определяющих аргумент
суффиксов (1 или v). Суффиксы поиска (р) и наследо-
вания среды (е) являются необязательными. Комбини-
рованная длина передаваемых аргументов не должна
превышать 128 байт. При ошибке функции ехес возвра-
щают значение —1.
void exit(int st) —завершает программу со статусом
(состоянием выхода) st;
struct tm * localtime(const long*t) —преобразует
354
дату и время в значения полей элементов записи типа tm;
возвращает указатель на эту запись;
spawn...— группа функций для создания и запуска
порожденных процессов:
int spawnl (int m, char * p, char * argO,...);
int spawnle(int m, char * p, char * argO,...);
int spawnlp(int m, char*p, char * argO,...);
int spawnlpe(int m, char*p, char * argO,...);
int spawnv(int m, char * p, char * argv [ ] );
int spawnve(int m, char*p, char* argv [ ], char**
env);
int spawnvp (int m, char * p, char * argv [ ] );
int spawnvpe (int m, char*p, char* argv [ ],
char ** env).
Функции в семействе spawn... создают и запускают
порожденные файлы (дочерние процессы). При этом, как
и в случае функций семейства ехес..., требуется достаточ-
ный объем памяти. Значение m определяет следующие
возможные режимы вызова: Р_____WAIT — сохраняет роди-
тельский процесс, пока порожденный процесс не закан-
чивает работу; Р__NOWAIT — продолжает запуск роди-
тельского процесса совместно с порожденным процессом;
Р__OVERLAY — перекрывает порожденным процессом
память, прежде занимаемую родительским процессом (как
и для функций семейства ехес...). Переменная р и суф-
фиксы 1, v, р, е используются так же, как и для функций
семейства ехес... При ошибке функции spawn ... возвра-
щают значение —1.
int stime(long * t) —функция установки времени;
при успешном завершении возвращает значение нуль;
int system (const char * com) — выполняет команду
операционной системы, определенную строкой, на которую
указывает сот, и продолжает выполнение текущей про-
граммы;
long time(long * t) — дает текущее время в секундах,
которое отсчитывается от 00 часов 1 января 1970 г. Оно
запоминается в виде значения переменной *t и возвра-
щается функцией time.
Ниже приводится пример программы, демонстрирующей исполь-
зование функций семейств ехес... и spawn...:
«include <stdio.h> /» Пример использования функций «/
^include (process.h> /* семейств ехес и spawn */
statusfint val)
( if (val-" -1)
355
printfl"Ошибочное начало подчиненного процесса^'),
else if (val > 9)
printff"Оиибочное заверявшие подчиненного процессам")
)
nil! 1
{ int sost;
char »envp[] = 1 “FATH-C:;D:\\C;D:\\SKL" I;
char ipalhnaae = "D:\\SKL\\VKL.EXE",
char *args( ] - { "VKL.HE”,
"ЕССР,_г._tact',
"йнвскив_радиотеиический_нвсгнт»т',
"КафедраJ „8J", KCLL 1;
/» пример использовании функции spawnl »/
printf!"Пример использования функции spawnl:\n'),
status(spa»nl(P_WAIT,pathnaae,argsfO],args[1J.HDbL)),
/» пример исподьзонавня функции spaxnv »/
printf!'Пример использовании функции spawvAn"),
status(spawnv(P JH IT,pathname,args)),
/» пример использовании функции spamle »/
printft"Пример ксподьзовавия функции spasnle:\n");
status! spawnle(P_WAIT,pathaaee > args[0],args[1],KOLL,envp));
/» пример использования фркции spamvpe </
printf(’BpHuep испильзовавия функции spamvpe:\n" >;
status (spamvpe if ЛИ, pathname, args, envp));
puts!"Визов подчиненного процесса");
пример использования функции systei »/
system!'pr'); system!"dir \katal");
/< пример использования функции ехес! »/
sosk ехес 1( "CBItD.EXE", ’CRILD.EXE", "аргумент J', "аргумент X' .NOLL I
printf!"Окибка.- W sost)'
Программы, реализующие дочерние процессы, помещены в файл
VKL.EXE (для функций spawn...), PR.EXE (для функции system) и
CHILDEXE (для функции execl). Тексты этих программ приведены
ниже;
linclude <stdio.h> /» эта программа помещена в файд Ш.С »/
•include cstdlih.h)
mainfini argc.char argvEJ)
{ ini i; char »path;
/» назначение указателе path адреса стропи операционной
средн (функция getenv) »/
path : getenv!"PATH"); о;
for(i=0;i<argc;i+t)
printf("argv[Xdj: is\n",i,argv[i]J;
if(path) printf("PATH : Xs\iT,path);
exit(O); I
•include (atdio.h) /I эта iporpaxxa помещена в файл PS.С I/
ria in ()
[ pstsdpixep внзова згой програиин с похоцы *
'функция systei’); )
linclude <stdio.h> /» эта программа помещена в файл CH1LB.C I/
ainfint argc,char »argv[])
( int i;
printffBHnoxHHetcH подчнхенннй процесс\п");
for(i=0;icargc;its)
printf(’argv[td): Xs\n",i,argv[.i]); )
35 6
Результаты работы программ представятся в следующем виде:
Пример вспошонави фуниции spanl:
argv[0]:
argv[IJ:
PATH : C:\;C:\DOS;C:\«OHTOM;C:\C\TC.O;C-.\iroBG01Dg;Ci\lttS!f
Пример всподьзоваш функции span?:
argv[O];
argv[IJ:
argv[2J:
argv[3]:
PAT8 = C.\;C-\DOS;C:\HOeTOH;C.-\C\TC.O;C:\HOBCOIDK;C.-\iIASH
Пример испохьзоваиия фуикции apamle:
argv[0]:
argv[I]:
PATH -- C:\;B:\C;B:\SKl
Пример исподьзовави функции spa мире;
argv[0]:
argv[I]:
argv[2]:
argv[3J:
PATH : C;\;D.\C,D:\SKb
Вызов подшейного ipogecca
Пример внзова этой программы с помовьв функции syslei
Volpse is drive A lias ао label
Directory of A:\KATAL
<D1R> <D1H> 3-02-90 3-02-90 lO:I8p lO'.IOp
спив OBJ 604 3-02-90 !0:02p
спив ПК 9627 3-02-90 l0:02p
Р8 tn 7634 3-02-90 I0.02P
VKL Ш 9803 3-02-90 Ю:02р 6 File(s) 380416 bytes free
Выподияется подчииенинй процесс
argv[0J: A:\CniLD.Ш
argvilj: аргументу
argv[2J: артуиеит_2
10.2.8. Функции для работы с каталогами
Перечислим функции для работы с каталогами:
int chdir (const char*p) — смена текущего каталога
(поддиректория) ; имя нового текущего каталога задается
строкой р; возвращает значение нуль при успешном за-
вершении; при ошибке —1;
int getcurdir(int d,char * dr) —устанавливает имя dr
текущего директория для указанного диска d (здесь
d=0 для диска, заданного по умолчанию, d= 1 для дис-
ка A, d=2 для диска Вит. д.); возвращает нуль при
успешном завершении и — 1 при ошибке;
int getdisk(void) — возвращает номер текущего диска
(здесь диск А имеет номер 0, диск В — номер 1 и т. д,);
357
int mkdir (const char * p) — создает новый подкаталог
с именем р; возвращает нуль при успешном завершении
и — 1 при ошибке;
int rmdir (const char *p) — удаляет подкаталог с име-
нем р; возвращает нуль при успешном завершении и —1
при ошибке;
int setdisk (int d) — устанавливает текущий диск
(здесь d=0 для диска A, d= 1 для диска Вит. д.); воз-
вращает общее число доступных дисков.
Ниже приводится пример программы, демонстрирующей функции
для работы с каталогами; здесь же показано применение многих функ-
ций, описанных в п. 10.2.7:
UlBcltide <dir.b> /» пример использования функций для »/
«iaclude <hios.h> /» работа с каталогами, а такхе ие- »/
«include /» которых функций, осдествлимх »/
ais() /» взаимодействие с ОС и аппаратурой »/
{ long vr, I»; double nvr; ini s,k;
cbar sdir(50J; struct la »p;
/» создание в текши директория поддиректория priaer »/
kdir("pr iner");
/» установка текучего поддиректория priaer Ч
chdirf"pr iier");
/♦ определение текущего диска »/
printf( "Текши диск: %d\n",geldisk!));
/» определение текущего директора! »/
getcurdirt4,sdir);
printf ("Текши директорий: Ss\n',sdir);
chditС.."); [Ч переход в предвествуэций директорий »/
/» определение текучего директория »/
getcurdirf4,sdir);
printf("Текудий директорий: Щи",sdir);
radlrfpriaer'); /» удаление поддиректория priter »/
/» определение маршрута к файлу COKKAHD.COH (при условии,
что ои бад определен ранее в команде path) »/
printf("Иарврут к файлу COHHAND.COH-. Xs\n",
searchpath('COffiAND.COH-));
/» чтение скзи- и ASCll-кода нажатой клавиви »/
ргЫ(("СКЭ8-код: Хд (десятичный: ",(s=k=hioskey(0),
s>>8)); prInif("*d)\B",s>>8)-, /» нажать лабув кдавияц,,»/
printf("ASCll-KOg: tx (десятичный: kd)\n".ktOxff,k&255");
/» определение разиера паияти »/
printf("Размер памяти в килобайтах.- M\a",biosneaory());
/» определение вреиеии 8I0S »/
printf("BpexH, отсчитанное 18,2 раза в секунду от "
"полночи: tidin'",klosti»e(0,0));
/» определение яремеии работа програмин »/
printf("Время работа програимы: kld»(I/18,2) сек\п",
(vr=clock(),vr));
nvr-(douhle)vr/I8.2; /» округление в иеиыук сторону »/
printfCBpeHa работы програмиы: klf сек\п”,nvr);
/» получение времени, отсчитанного от 0 часов I января
1370 года (в секундах) »/
printf("Вренн: kld\n",tiie(tti));
358
/» преобразование дата и яреиеии в значения шей записи р »/
p=localtine(&tm);
printf(Toj: Xd; несяц; И; день: И; часа: Х1; иииута: '
4d; секунды: %Л.\пДеиь года: И; день иедеди: Xd"
'\n’,p->tijear,p->l>JOn»l,p->t»jday,p->t»Jiour,
p->tajin,p->t»_sec,p->tBjda7tI,p->lB_»day)',
/» преобразование дата и вренеии в ASCll-строуу »/
printffTetyiae дата и вреия: Xs",ascti»e(p));
/» получение строки с тощей датой и вреиеиеи »/
printf("Текудие дата и вреия: Xs\n",ciiaef&tn)); )
Результаты работы этой программы представятся в следующем
виде:
Текущий диск: 2
Текущий директорий: TC\WOBK\PH1HEH
Текущий директорий: ТС\ЯОНК
Марщрут к файду COHHAHD.COB: C:\COHHAHD.COK
СКЭЕ-код: I (десятичнай: I)
ASCII-код: 1Ь (десативй: 27)
Размер памяти в килобайтах: 633
Время, отсчитанное 18,2 раза в секунду от полночи: 1482121
Время работа нрограммн: 242»(1/18,2) сек
Время работа программы: 13.296703 сек
Вреия: 636(35406
Год: 90; иесиц: 3; деиь: 2; часы: 22; мину иг 36; секумдн: 46.
День года: 61; день недели: 5
Текущие дата и время: Fri Наг 02 22:36:46 1990
Текущие дата и время: Fr i Наг 02 22:36:46 1990
10.2.9. Специальные функции
Перечислим специальные функции:
void *bsearch (const void *k,const void *str, unsigned n,
unsigned w, int (*srav( )) —функция двоичного поиска.
При наличии числа к в массиве str, состоящем из п эле-
ментов длиной w байт, возвращается указатель на него
(на элемент, совпадающий с к); при отсутствии этого
числа возвращается NULL (здесь srav — функция сравне-
ния, которая возвращает нуль при равенстве чисел);
int fstat(int h, struct stat *sb) — получает информа-
цию об открытом файле с номером h (handle); подобна
рассматриваемой ниже функции stat;
char *getenv (const char *name) — получает указатель
на строку из окружения MS-DOS; при успешном завер-
шении возвращает указатель на строку, связанную с име-
нем (командой) пате либо NULL, если пате не опреде-
лена в окружении MS-DOS. Пример использования этой
функции для команды path был приведен в п. 10.2.7;
void *lfind(const void *k, const void *str, unsigned n,
unsigned w,int (*srav)()) — функция поиска, осущест-
вляет поиск в массиве str числа, на которое указывает к;
возвращаемые значения подобны bsearch;
359
void longjmp(jmp__buf bj, int r) — функция длинного
перехода, перед которой должен быть осуществлен вызов
функции setjmp вида v = setjmp(bj) (здесь bj — запись
типа jmp___buf, определенная в файле setjmp.h и сохра-
няющая значения регистров микропроцессора). Функция
longjmp позволяет выполнить длинный переход из одного
программного модуля в другой и тем самым строить
функции с несколькими точками входа. Второй аргумент
в longjmp — это значение, передаваемое в v после длин-
ного перехода; оно не может быть нулем;
unsigned long__Irotl (unsigned long val, int count) —
вращает длинное значение val влево на count бит; воз-
вращает повернутое значение val;
unsigned long__Irotr (unsigned long val, int count) —
вращает длинное значение val вправо на count бит; воз-
вращает повернутое значение val;
void *lsearch (const void *k, void *str, unsigned n,
unsigned w, int (*srav)()) — функция поиска, подобная
Ifind;
void qsort (void *str, unsigned n, unsigned w, int
(*sraw)()) — сортирует объекты с использованием быст-
рого алгоритма (здесь str — указатель на сортируемый
массив; п — число элементов в массиве; w — их длина;
srav — указатель на функцию сравнения, которая воз-
вращает 1, если первый объект больше второго; 0— при
равенстве объектов и —1, если первый объект меньше
второго). По завершении работы функции str будет ука-
зывать на отсортированный массив;
int putenv (const char *name) —добавляет строку
name в текущее окружение MS-DOS; возвращает 0 при
успешном завершении и —1 при ошибке;
int raise (int sig) — посылает сигнал в выполняемую
программу. Программа, содержащая raise, может послать
сигнал sig, для того чтобы активизировать некоторый
процесс. Типы сигналов для переменной sig'':oпpeдeлeны
в файле signal.h;
int rand (void) — возвращает псевдослучайное число
в интервале от 0 до 32767;
void randomise () — инициализирует генератор псев-
дослучайных чисел;
unsigned ___roti (unsigned val, int count), unsigned
__rotr (unsigned val,int count) — подобны функциям
__Irotl и _Irotr, но работают с беззнаковыми целыми
числами;
int setjmp(jmp_buf bj) —определяет точку входа в
360
программный модуль и вызывается перед функцией
longjmp; запись bj типа jmp___buf определена в файле
setjmp.h;
void (*signal(int sig, void (*func) ())) (int) — воз-
буждает процесс func, когда активизирован сигнал sig.
Типы сигналов sig определены в файле signal.h. Сигналы
вырабатываются, когда возникают соответствующие усло-
вия либо после вызова функции raise;
int stat (char *path, struct stat *sb) — получает инфор-
мацию об открытом файле, заданном именем path (до-
полненным маршрутом к файлу). Запись sb типа stat
определена в файле stat.h и содержит необходимые дан-
ные. Возвращает 0 при успешном завершении и — 1 при
ошибке;
type va__arg(va__list ap, type) — здесь type —задан-
ный тип. Эта функция, реализованная как макрос в файле
stdarg.h, последовательно возвращает аргументы из пере-
менного списка. Когда va_arg использована первый раз,
она возвращает первый аргумент в списке. При каждом
последующем вызове возвращаются очередные аргу-
менты. Функция va___arg реализует эти действия с по-
мощью первого, упоминаемого в другой функции va_start,
объекта ар, который затем увеличивается для выбора
очередного элемента данных. Функция va_arg использует
тип type, чтобы находить следующий элемент данных
с учетом требуемого масштабирования. Список ар типа
va__list определен в файле stdarg.h; в нем хранится
информация, необходимая va____arg и va___end. Когда
функция принимает переменный список аргументов, он
должен быть описан как va list;
void va__end (va__list ap) — этот макрос помогает
вызванной функции осуществить нормальный возврат.
Его необходимо вызывать тогда, когда va__arg считает
все аргументы. Макрос va__end не возвращает никаких
значений;
void va__start (va__list ap,p) —организует доступ
к переменному списку аргументов и устанавливает ар так,
чтобы выбирался первый элемент. Назначение параметра
ар пояснено при описании функции va______arg. Объект
р является именем последнего фиксированного пара-
метра, переданного вызванной функции. Функция (мак-
рос) va start не возвращает никаких значений. Она
должна быть использована до первого вызова va____arg
или va end.
361
Рассмотрим примеры использования некоторых специальных функ-
ций. Первая программа демонстрирует применение va-функций:
linclude <stdio.h> /» аример использования va-фуикций I/
linclude <stdarg.h>
void fualchar
( long rez; vajist ap;
int arg,op; »a_start(ap,f);
pulsfKaiHte tan операции: 1 - t; 2 -- »');
scan f("Xd",4op);
iflop-l) rez-0; else rez=l;
«hile((arg=va_arg(ap,int))1-MDLL) (
aHitch(op) ( *
case 1: ret*=arg; break;
ca*e 2: rezt-arg; break;
default: ри!з('Певериий tin операции'); exit!); ) )
printf(f,rez); 1
ain()
( funCWnyxitat l:\Wld\n",l,3,5,HI)LL);
funfitPesyxbtat 2:\Uld\n", 1,3,5,7,3,HDLL); )
Ниже представлены результаты ее работы:
Unite tin операции: 1 -- t; 2 — *
2
Результат 1: 15
Каше тип операции: 1 - ь; 2 - t
1
Результат 2: 25
Вторая программа показывает использование функций setjmp
и longjmp:
^include <stdio.Ь/ /» прииер использования Функций »/
linclude <setj»p.h> /» setjap a longjap */
int v; jap.buf bj;
aaini)
( /» первоначально setjnp установит v=0 »/
vrsetjaptbj);
if(v!-0) ( /» это условие будет выполниться только
после вызова iongjsup в функции sub >/
printf("Цинний переход со зиачениеи.- Xd\a",v);
exit(v); 1
/| сначала будет напечатано сообщение в puts »/
putsfBanoB функции sub"),
snb(); /» 1 функции sub будет выполнен дхиииай переход
и оператору if и при этой v=l Ч !
sub() /» функции, осуцесгнлнпиан длинная переход »/
( longj«p(bj,I); )
/л второй аргумент в longjap - это значение, передаваемое
в и (оио ие нохет быть нулей, поскольку при этой v
все равно будет равно единице) «/
Результаты ее работы:
вызов Функции sub
Длинный переход со зиачениеи: 1
362
Третья программа иллюстрирует применение функций сортировки
и поиска:
(include (stdio.b) /г пример исаопзовааии функций т/
finclude (stdlib.h) /» сортировки к поиска •/
int sravfunsigned char »a,unsigned char Th)
( iffa > th) retarnfl};
else if(»i ( »b} return(-l);
else retarnfO}; )
naia()
( unsigned char str[30],tu,k;
unsigned n; int t;
for(i=0;i(90;iH) str{i]=rand();
puts('\n\t\t Встодаае скучайиие чисда\п');
f or (i-0;i(90;ift)
printffX3dJc',rtr(i],((l+l)M0)!' ':'\b'};
/» сортировка чиееа в иорядке иг возрастания »/
qsort(str,90,1,srav);
puts('\п\1\1Подученпые отсортированные числа\п"};
fot( 1-0; i (90; iH)
printfCk3dkc',str[l],((iH)J18)?' ;>•);
putsfB negate u n o');
scanffW.tk);
/« яри аатичии часта k в «ассизе возарадается указатель (и)
иа aero, при отсутствии этого чисда возврадается HOLL т/
u=bsearch(4k,str,90,1,srav);
if(u=--H0LL) putsfBBejeaaoro чиста нет в иассиве*}; else
prlntffPacctoaaae (в баатад} or начата иассива: %р\п‘
'(иестиадцатермчиое чисдо}\п",u-str);
putsfB ведите ч а с д о');
scanf("Xd" ,4k}; п-90;
/» функции Ifind осудествдяет иоиск в «ассизе чаем, «а
которое /измает k (лереиенна» п имеет безэпакодый
иедый ran); возврадаеиие значении подобии bsearch '/
u-lfind(Jk,str,4n,1,srav);
if(u::H0Ll) putsfBBejeaaoro чясда нет в иассаве'); else
printffPacctoaaae (в байтад) от аачада иассияа: кр\п'
"(вестаадцатерачиое чисдо)\п",u-str); )
Результаты ее работы представлены ниже:
Нсюдиие сдучайвие чиста
90 130 230 66 136 205 187 15 164 150 44 222 243 95 60 80 36 97
191 215 239 209 22 161 238 117 44 203 187 104 177 195 75 41 150 254
139 235 201 220 57 24 50 216 4 39 238 244 231 159 203 100 195 108
4 122 59 98 62 209 213 15 194 189 78 198 253 243 62 233 53 117
237 118 141 193 116 212 60 58 24 224 10 214 227 51 12 10 132 183
Водучеиине отсортнрованнне часта
4 4 10 10 12 15 15 22 24 24 36 39 41 44 44 50 51 53
57 58 59 60 60 62 62 66 75 78 80 90 95 97 98 100 104 108
116 117 117 118 122 130 132 136 139 141 150 150 159 161 164 177 183 187
187 189 191 193 194 195 195 198 201 203 203 205 209 209 212 213 214 215
216 220 222 224 227 230 231 233 235 237 238 238 239 243 243 244 253 254
Введите чисто
15
363
Pacctoine (в байта!} от ичаи xaceesa: 0005
(«естиадцатеричиое чиеао}
Введите число
66
Расстояние (в байта!) от начата пассива: 0019
(иестиадцатеричюе чисто)
10.3. СТАНДАРТНЫЕ ПРОЦЕДУРЫ
И ФУНКЦИИ ЯЗЫКА ПАСКАЛЬ
10.3.1. Математические процедуры и функции
Опишем вкратце математические процедуры и функции
языка ПАСКАЛЬ. Тип передаваемых значений в списке
параметров для каждой подпрограммы, как правило, ука-
зывается через двоеточие. В том случае, когда тип пара-
метров является неоднозначным, он будет оговариваться.
Для подпрограмм-функций обязательно определяется
тип возвращаемого значения (тип функции).
В языке ПАСКАЛЬ определены следующие матема-
тические функции:
abs (к) — возвращает абсолютное значение аргумента
к, который для данной функции может быть целым либо
вещественным; тип возвращаемого значения определяется
типом аргумента;
arctan(x:Real)—функция арктангенса; тип резуль-
тата — вещественный;
cos(x:Real)—функция косинуса; значение аргумен-
та задается в радианах; функция возвращает веществен-
ное значение;
exp(x:Real) — вычисляет значение ех (экспоненциаль-
ная функция); тип результата — вещественный;
frac(x.Real) — возвращает дробную часть аргумен-
та х в виде вещественного значения;
int(x:Real) —возвращает целую часть аргумента х
в виде вещественного значения;
ln(x:Real) — возвращает значение натурального лога-
рифма х(1п х); тип функции — вещественный;»:
pi — возвращает значение 3714159...;
sin(x:Real) —функция синуса; аргумент х задается
в радианах; функция возвращает вещественное значение;
sqr (к) — возвращает значение к2; аргумент к может
быть как целого, так и вещественного типа и соответ-
ственно определяет тип возвращаемого значения;
sqrt(x:Real) —возвращает значение д/х; результат
имеет вещественный тип.
Данную группу подпрограмм можно дополнить двумя
процедурами:
364
dec(o[; kLongint]); — уменьшает значение о на 1 еди-
ниц. Параметр о может быть значением любого перечис-
ляемого типа (Char, Boolean, а также любой целый,
порядковый либо интервальный). Например, для цело-
численного аргумента о процедура dec(o,l); аналогична
оператору о: = о— 1; Параметр 1 является необязатель-
ным, при его отсутствии значение о уменьшается на еди-
ницу;
inc(o[; kLongint]);— наращивает значение перемен-
ной о на 1 единицу. Параметр о — значение любого пере-
числяемого типа. Второй параметр 1 может отсутствовать,
при этом inc(о); увеличивает значение о на единицу.
10.3.2. Функции порядка и преобразования типов
Перечислим функции определения порядка и преобра-
зования типов:
chr(b:Byte) — возвращает символ (тип функции
Char), код которого указан в качестве параметра Ь;
odd (1 :Longint) —проверяет аргумент на четность;
возвращает значение True, если 1 — нечетное число, и
False — в противном случае; тип функции — Boolean;
ord(o) — возвращает порядковый номер значения о в
списке значений соответствующего типа (здесь о —
переменная или выражение любого перечисляемого типа,
а функция возвращает значение типа Longint);
pred(o) — возвращает значение, предшествующее о в
списке значений соответствующего типа; аргумент о может
быть значением любого перечисляемого типа и опре-
деляет тип возвращаемого значения;
round(x:Real) —округляет аргумент х до целого зна-
чения; тип результата — Longirt;
succ (0) — возвращает значение, следующее за о в спи-
ске значений соответствующего типа; тип параметра о мо-
жет быть любым перечисляемым и совпадает с типом
результирующего значения;
trunc(x:Real) — возвращает целую часть аргумента в
виде значения типа Longunt.
10.3.3. Процедуры и функции для работы с файлами
В языке ПАСКАЛЬ определены следующие подпрог-
раммы для работы с файлами:
append (Var f:Text); — процедура открывает текстовой
файл для дополнения;
assign (f: File; s:String);— процедура устанавливает
365
соответствие между файловой переменной f и реальным
файлом на диске, спецификация которого определяет-
ся строкой s;
close(f:File); — процедура закрывает файл f;
eof (f:File) —функция возвращает значение True, ес-
ли достигнут конец файла, и False — в противном
случае;
eoln(f:Text) — функция возвращает значение True, ес-
ли достигнут конец строки в текстовом файле, и False —
в противном случае;
erase(f:File); — процедура удаляет файл на диске;
filePos(f; File) — функция возвращает значение указа-
теля текущей позиции файла f (номер текущего компонен-
та); тип возвращаемого значения — Longint;
fileSize(f:File) — функция возвращает значение (Lon-
gint) текущего размера файла f (количество компо-
нентов) ;
flush(Var f:Text); — процедура очищает буфер тек-
стового файла при открытии для записи;
rename(f:File; s:String); — процедура переименовыва-
ет дисковый файл, связанный с файловой перемен-
ной f; новое имя определяется строкой s;
reset (f:File); — процедура открывает файл f для
чтения;
rewrite(f: File); — процедура открывает файл f для
записи.
seek(f:File; kLongint); — процедура перемещает ука-
затель текущей позиции файла f к компоненту с номе-
ром 1 (нумерация компонентов начинается с нуля);
seekEof(Var f:Text) — функция соответствует Eof (f) с
той лишь разницей, что при определении состояния
конца файла игнорируются все пробелы, символы та-
буляции и признаки конца строки в текстовом файле;
функция совпадает с Eoln(f), за исключением того, что
при определении состояния конца строки пропускаются все
пробелы и символы табуляции;
truncate(f:File); — процедура отбрасывает все компо-
ненты файла f, находящиеся за указателем текущей пози-
ции файла (текущий компонент становится последним)
10.3.4. Процедуры и функции
для работы со строками символов
Для работы со строковыми переменными в языке
ПАСКАЛЬ определены следующие процедуры:
366
delete (Var s:String; n 1, n2:Integer); — удаляет из стро-
ки s п2 символов, начиная с позиции п1;
insert(s 1 :String; Var s2:String; n:Integer); — вставля-
ет строку st в строку s2, начиная с позиции п;
str (к [формат]; Var s:String); — преобразует число к
(целое либо вещественное) в строковое значение s.
Можно указать формат преобразования, например к:5,
при этом значение к оформляется в строку длиной
5 символов, которая слева при необходимости допол-
няется пробелами;
val (s: String; Var k; Var n: Integer); —преобразует
строку s в числовое значение k — целое либо веществен-
ное (здесь п — код преобразования, который формируется
как номер позиции первого, отличающегося от цифры сим-
вола в строке s); при успешном преобразовании п = о.
Далее перечисляются встроенные функции для обра-
ботки строковых переменных:
со neat (s 1, s2, s3...:String) — принимает значение стро-
ки, полученной в результате конкатенации (объеди-
нения) строк, указанных в качестве параметров;
copy(s:String; nl, n2;Integer) — принимает значение
подстроки размером п2 символов, выделенной из строки
s, начиная с позиции nl;
length (s:String) — возвращает текущую длину строки
s; тип возвращаемого значения — Integer;
pos (si, s2:String) — возвращает номер позиции строки
s2, начиная с которой в s2 полностью входит строка si,
10.3.5 Функции для работы с адресами
и регистрами микропроцессора
Перечислим встроенные функции для определения
адресов переменных и обращения к внутренним регист-
рам микропроцессора:
addr(a) —функция (типа Pointer) возвращает адрес,
по которому переменная а хранится в оперативной
памяти (здесь а — переменная любого существующего
типа, это может быть также идентификатор процедуры
или функции);
cseg — возвращает текущее содержимое регистра
DS; тип результата — Word;
dseg — возвращает текущее содержимое регистра DS;
тип результата — Word;
ofs(a) — возвращает значение смещения адреса, по
которому переменная а размещается в оперативной
367
памяти (здесь а — переменная любого типа, функция
имеет тип Word);
ptr(wl, w2:Word) —функция (типа Pointer) возвра-
щает значение адреса, заданное сегментным адресом
wl и смещением w2;
seg(а) — возвращает сегментную часть адреса пере-
менной а; тип возвращаемого значения —Word;
sptr — возвращает текущее содержимое регистра SP;
тип возвращаемого значения — Word;
sseg — возвращает текущее содержимое регистра SS;
тип возвращаемого значения — Word.
10.3.6. Процедуры и функции для работы
с экраном в текстовом режиме
Приведем краткое описание процедур и функций для
работы с экраном в текстовом режиме. Все описанные
ниже процедуры определены в библиотечном разде-
ле CRT:
ClrEol; — процедура удаляет символы в строке, спра-
ва от позиции курсора;
ClrScr; — процедура очищает экран и перемещает
курсор в верхнюю левую позицию;
Delay(w: Word); — процедура организует задержку
выполнения программы на w мс;
Del line — процедура удаляет строку символов, на ко-
торую указывает курсор на экране;
GotoXY(x, y:Byte); — процедура перемещает курсор в
позицию экрана с координатами х (номер позиции в
строке) и у (номер строки);
High Video; — процедура устанавливает режим повы-
шенной яркости вывода символов на экран;
InsLine; — процедура вставляет пустую строку на
экране в позицию, определяемую расположением кур-
сора;
KeyPressed — функция (типа Boolean) 'Возвращает
значение True, если на клавиатуре была нажата какая-
либо клавиша, и False — в противном случае;
LowVideo; — процедура устанавливает режим пони-
женной яркости вывода символов на экран;
NormVideo; — процедура устанавливает режим нор-
мальной яркости вывода символов на экран;
NoSound — процедура прекращает подачу звукового
сигнала;
ReadKey — функция (типа Char) считывает символ с
клавиатуры;
368
Sound (w: Word); — процедура вызывает подачу зву-
кового сигнала с частотой w Гц;
TextBackGround (b: Byte); — процедура устанавливает
цвет фона; значение b изменяется от 0 до 7;
TextColor (b: Byte);—процедура устанавливает цвет
вывода символов на экран; значение b изменяется от
О до 15;
WhereX — функция возвращает координату х (но-
мер позиции в строке) текущей позиции курсора;
WhereY — функция возвращает координату у (номер
строки) текущей позиции курсора;
Window(xl, yl, х2, y2:Byte);— процедура создает
на экране текстовое окно заданного размера (xl,
у! — координаты верхнего левого угла окна; х2, у2 —
нижнего правого угла).
10.3.7. Процедуры и функции
для динамического распределения памяти
В языке ПАСКАЛЬ определены следующие стандарт-
ные процедуры и функции для динамического распре-
деления памяти:
Dispose(Var p:Pointer); — процедура освобождает
блок динамической памяти, ранее выделенный для пере-
менной, на которую указывает р;
FreeMem(Var p:Pointer; w:Word); — процедура осво-
бождает ранее выделенный блок динамической памяти
размером w байт, начиная с адреса р;
GetMem(Var p:Pointer;w:Word); — процедура выде-
ляет блок динамической памяти заданного размера (w
байт), начиная с адреса р;
Mark (р: Pointer); — процедура присваивает пере-
менной р значение текущего указателя динамической па-
мяти;
MaxAvail — функция (типа Longint) возвращает раз-
мер (в байтах) максимальной непрерывной свободйой
области динамической памяти;
MemAvail — функция (типа Longint) возвращает
общий размер (в байтах) свободной динамической па-
мяти;
New (Var p:Pointer); — процедура выделяет блок дина-
мической памяти для размещения переменной, на которую
указывает р.
369
10.3.8. Процедуры и функции для взаимодействия
с операционной системой
Рассмотрим встроенные процедуры для работы с ди-
ректориями, которые определены в библиотечном разделе
SYSTEM:
ChDir (s:String); — осуществляет смену текущего ди-
ректория; имя нового директория определяется значением
строки s;
GetDir (b:Byte; Var stString);— присваивает перемен-
ной s наименование текущего директория на указанном
диске; значение b определяет диск: 0 — текущий, 1 — А,
2 — В и т. д.;
MkDir (s:String); — создает новый поддиректорий, имя
которого определяется значением строки s;
Rmdir (s:String) —удаляет указанный поддиректорий
на диске.
Остальные процедуры и функции этой группы опре-
делены в разделе библиотеки DOS, т.е. требуется опера-
тор USES DOS; в начале программы для их использо-
вания:
GetlntVec (b:Byte; Var р: Pointer); — процедура при-
сваивает переменной р адрес указанного вектора преры-
вания; параметр b определяет номер вектора прерывания
(0...255);
Intr(b:Byte; Var г: Registers); — процедура обраба-
тывает указанное прерывание (здесь b — номер преры-
вания (0...255); г — переменная типа Registers, опреде-
ленного в разделе библиотеки DOS следующим образом:
Type Registers =
record
case Integer of
0- (Al,BI,Ci,DI,ПР,SI,DI,DS,IS,Flags: Word);
1: (At,An.BL,Bn,Cb.Cn,DL,Dn. Byte);
end;
Е1еред выполнением процедуры Intr полям записи г, свя-
занным с содержимым внутренних регистров микропро-
цессора, присваивают требуемые значения. По заверше-
нии обработки прерывания содержимое регистров поме-
щается обратно в запись г);
MS Dos (Var r:Registers); — процедура выполняет пре-
рывание 21 is (см. процедуру Intr);
SetlntVec(b:Byte; Pointer); — процедура устанавли-
вает указанный вектор прерывания (0...255) по адресу р;
DiskFree(w:Word) —функция (типа Longint) воз-
370
вращает число свободных байтов на указанном диске;
w определяет диск: 0 — текущий, 1 — А, 2 — Вит. д.;
Exec (s 1 ,s2:string); — процедура выполняет указан-
ную команду операционной системы, s2 определяет ко-
мандную строку, si — спецификацию файла, который обе-
спечивает выполнение указанной команды;
FindFirst(s:String;b:Byte; Var z:SearchRec); — проце-
дура просматривает директорий до первого обнаружения
указанного файла и возвращает информацию о нем
Строка s определяет шаблон для просмотра директория.
Параметр b позволяет установить, какие специальные
файлы (системные, скрытые и т. п.) включать в просмотр,
кроме обычных. Возможные значения этого параметра
определены в разделе DOS. Полная информация о файле
возвращается переменной z типа SearchRec, который
также определен в библиотечном разделе DOS;
FindNext(Var z: SearchRec); — процедура выдает
информацию о следующем файле из директория, опре-
деленного ранее в процедуре FindFirst;
GetDate(Var wl, w2, w3, w4: Word); — процедура
возвращает текущую дату, установленную в операционной
системе (wl —год, w2 — месяц, w3 — день, w4 — день
недели);
GetFAttr(f: File; Var b:Byte); — процедура возвра-
щает переменной b атрибуты файла f; константы, соот-
ветствующие различным атрибутам, определены в модуле
DOS; файл f при выполнении этой процедуры должен быть
закрытым;
GetFTime(f:File; Var LLongint); — процедура возвра-
щает дату и время Ьоздания файла в упакованном форма-
те (4 байта);
GetTime(Var wl ,w2,w3,w4:Word); — процедура воз-
вращает текущее время, установленное в операционной
системе (wl — часы, w2 — минуты, w3 — секунды, w4.—
сотые доли секунды);
PackTime(Var d'.DateTime; Var kLongint); — проце-
дура преобразует запись d типа DateTime, содержа-
щую информацию о дате и времени создания файла, в
упакованный формат 1 (4 байта); тип DateTime
определен в разделе библиотеки DOS следующим об-
разом:
Type DateTiae - record
Tear,Honth,Day,Поаг,H m,Sec: Korn;
end;
371
SetDate(w 1 ,w2,w3,w4: Word); — процедура устанав-
ливает новую дату в операционной системе (wl — год,
w2 — месяц, w3 — день, w4 — день недели);
SetFattr (f.’File; b:Byte); — процедура устанавливает
атрибуты файла f; значение b определяет атрибуты файла
и формируется как сумма значений, соответствующих
различным атрибутам, определенным в DOS;
SetFTime(f:File; LLongint);— процедура устанавли-
вает дату и время создания файла; значение 1 определяет
дату и время в упакованном формате;
SetTime(w 1 ,w2,w3,w4: Word); — процедура устанав-
ливает новое время в операционной системе (wl —часы,
w2 — минуты, w3 — секунды, w4 — сотые доли секунды);
UnpackTime(l:Longint; Var d:DateTime); — проце-
дура преобразует упакованный формат 1 (4 байта), хра-
нящий дату и время создания файла, в запись d типа
DateTime, определенного в DOS (см. процедуру Pack-
Time) .
10.3.9. Специальные процедуры и функции
Перечислим специальные процедуры и функции:
BlockRead(Var f:File; Var c; wl :Word [; w2:Word]);—
процедура считывает определенное параметром wl коли-
чество записей из файла f и помещает их в область памяти,
начиная с первого байта размещения переменной с; файл f
является нетипизированным, ас — переменная любого
существующего типа. Параметр w2 может отсутствовать;
он используется для определения кода выполнения опе-
рации и принимает значение нуль при безошибочном
завершении передачи данных, в противном случае значе-
ние w2 будет равно числу правильно считанных записей
(до обнаружения ошибки);
BlockWrite(Var f:File; Var c; wl :Word [; w2:Word]); —
процедура переписывает содержимое ячеек йамяти, на-
чиная с первого байта области размещения переменной с,
в файл f на диске. Значение wl определяет количество
передаваемых записей; файл f должен быть нетипизи-
рованным, а с может быть переменной любого существую-
щего типа. Назначение параметра w2 аналогично опи-
санному в предыдущей процедуре;
Exit; — процедура вызывает немедленный выход из
текущего блока программы;
FiilChar(a; w.Word; ch); — процедура заполняет зна-
чением ch w байт оперативной памяти, начиная с первого
372
байта области памяти, которую занимает переменная
a (ch — значение типа Char или Byte);
Halt; — процедура останавливает выполнение про-
граммы и передает управление операционной системе;
Hi(n’.Integer) — функция возвращает значение (типа
Byte) старшего байта аргумента п;
Keep; — процедура вызывает завершение выполнения
программы, оставляя ее резидентной;
Lo(n:Integer) —функция (типа Longint) возвращает
значение младшего байта аргумента п:
Move(al,a2; w.Word); — процедура копирует область
памяти размером w байт, начиная с адреса, по которому
записан первый байт переменной al, в область, начиная
с первого байта переменной а2;
ParamCount — функция (типа Word) возвращает чис-
ло параметров, переданных программе через командную
строку;
ParamStr(w:Word) — функция (типа String) возвра-
щает параметр, стоящий в командной строке под номером
w, либо пустую строку, если значение w равно нулю или
больше ParamCount;
Random (n: Integer); — процедура генерирует случай-
ное число из интервала от 0 до п;
Randomize; — процедура инициализирует генератор
случайных чисел;
SizeOf(a) —функция (типа Longint) возвращает
объем (в байтах), который занимает переменная а; зна-
чение а может быть любого существующего типа;
Swap (n: Integer); — процедура меняет местами стар-
ший и младший байты переменной п;
UpCase(c:Char) —функция преобразовывает пропис-
ные буквы латинского алфавита в строчные; символы
вне диапазона a..z данной функцией не обрабатываются.
11. РАБОТА С ГРАФИКОЙ
11.1. ОБЩИЕ СВЕДЕНИЯ
Рассмотрим графические системы для двух популяр-
ных языков программирования: ТУРБО СИ (версия 2.0)
и ТУРБО ПАСКАЛЬ (версия 5.0).
В системе программирования ТУРБО СИ все необ-
ходимые определения для графического модуля даны
в файле graphics.h, и при выборе соответствующего
режима он должен быть включен в программу (4#include
(graphics.h)). Стандартные функции для графической
системы помещены в библиотеку graphics.lib, которая
должна быть подключена в режиме Options (см. гл. 9).
Используемые в системе программирования ТУРБО
СИ графические функции по своему назначению делятся
на несколько групп:
1) функции для подготовки графической системы и
перехода в текстовой режим;
2) функции для получения изображения на экране;
3) функции для установки параметров изображения
(вида штриховки, способа вычерчивания и толщины ли-
ний, размера текстовых символов, параметров окна
и т. п.);
4) функции для определения параметров изображения.
За начало координат экрана (х=0, у=0) принимается
его левый верхний угол. Значение х определяет число
точек, на которое смещается вправо от начала коорди-
нат указатель текущей позиции экрана. Значение у опре-
деляет аналогичное смещение вниз. При установке на
экране графического окна за начало координат принима-
ется левый верхний угол этого окна, который может быть
смещен относительно левого верхнего угла экрана. Угло-
вые величины задаются в градусах.
В графических функциях языка СИ применяются
записи и константы, определенные в файле graphics.h.
Для указания типа заполнителя используются цифро-
374
вые константы от 0 до 12 или соответствующие им сим-
волические константы (EMPTY_____FILL, SOLID_____FILL
и т. п.).
Для указания стиля линии служат цифровые констан-
ты от 0 до 4 или соответствующие им символические
константы (SOLID__LINE, DOTTED_LINE и т. п.).
Толщина линии задается с помощью констант: 1 (или
NORM_____WIDTH) — нормальная; 3 (или THICK__________
WIDTH) — утолщенная. Для указания типа текстовых
шрифтов используются цифровые константы от 0 до 4 или
соответствующие им символические константы
(DEFAULT_FONT, TRIPLEX__FONT и т. п.). В случае
выбора констант от 1 до 4 на текущем диске должны быть
файлы с соответствующими знакогенераторами (TRIP.
CHR, LITT.CHR, SANS.CHR, GOTH.CHR). Направление
текста задается с помощью констант: О (HORIZ_DIR) —
горизонтальное; 1 (VERT__DIR) — вертикальное. Размер
символа, устанавливаемый пользователем, задается кон-
стантой О (USER___CHAR___SIZE). Выравнивание текста
осуществляется с помощью констант: 0—относительно
левого края по вертикали (LEFT___TEXT) либо нижнего
края по горизонтали (BOTTOM_____TEXT); 1 (CENTER____
TEXT) — относительно центра; 2 — относительно правого
края по вертикали (RIGHT____TEXT) или верхнего края
по горизонтали (ТОР___TEXT).
Для задания операций с точками разных изображе-
ний, используемых при их совмещении, введены кон-
станты: О (COPY___PUT) — для простого перемещения
изображения на экран; 1 (XOR____PUT) — наложение с
выполнением операции Исключающее ИЛИ; 2 (OR_________
PUT) — наложение с выполнением операции ИЛИ;
3 (AND___PUT) — наложение с выполнением операции И;
4 (NOT___PUT) — перемещение изображения с отрица-
нием (инверсией)
Определим используемые записи:
struct linesettingstype (
int linestyle;
unsigned upattern;
int thickness; );
struct tentsettingstype (
int font;
int direction;
int charsise;
int horis;
int vert; );
struct filIsettingstype {
/» параметр» шии »/
/» ешь 1ИИИИ »/
/» битовый образ примитива
уииии из 16 точек »/
/» тоцииа »/
/» параметры текста »/
/» ирифт »/
/» иаправкеиие »/
/» размер симвока »/
/» выравнивание но горизонтам »/
/и выравнивание по вертмкаки ч/
/» параметры заполнении »/
375
int pattern; /» наполнитель »/
int color; ); /» цвет »/
struct palletetype ( /» даииие о текужей палитре »/
unsigned char size; /» чисю цветов i пантре »/
signed char colors(HAICOLORStl); )
/» даии»е о хацои цвете. Задаю
HAXCOLORS = 15 »/
struct pointtype ( /» координат» точки »/
int x, у; );
struct viewporttype ( /» параметра окна экрана »/
int left, top, right, bottom;
/к слева,сверху,справа,снизу »/
int clip; ); /» отсечеиие: -1 -- отсекать
О — иет »/
struct arccoordstype ( /* параметры дуги »/
int х, у; /» координат» центра дуге »/
int xstart, ystart, xend, yend; ) /* координат» иачада
(start) и конца (end) дуги »/
Язык программирования ПАСКАЛЬ располагает мощ-
ными средствами для работы с графической информацией:
в нем насчитывается около 80 стандартных графических
подпрограмм. Эти подпрограммы, а также все необходи-
мые для их использования определения собраны в раз-
деле GRAPH библиотеки встроенных процедур и функций,
которая находится в файле TURBO.TPL. Взаимодействие
с библиотекой осуществляет модуль GRAPH.TPU.
Подключение библиотечного раздела GRAPH к про-
граммному модулю производится с помощью оператора
USES GRAPH;. Он записывается в тексте программы
сразу же после строки, содержащей заголовок, и указы-
вает компоновщику на необходимость подключения
данного библиотечного раздела, вследствие чего все при-
веденные в нем описания становятся доступными в этой
программе.
Кроме того, для работы с графической системой не-
обходимо иметь на диске программы графических драй-
веров (файлы с типом BGI), а если требуется исполь-
зование текстовой информации, также программы, под-
держивающие различные шрифты в графическом режиме
(файлы с типом CHR).
Весь набор стандартных графических процедур и
функций можно разделить на следующие группы:
1) процедуры для подготовки графической системы
и перехода в текстовой режим;
2) процедуры для установки параметров изображения;
3) процедуры для получения изображения на экране;
4) процедуры и функции для получения параметров
изображения.
376
Приведем (так же, как это было сделано выше для
языка СИ) описания некоторых констант и типов данных,
определенных в библиотечном разделе GRAPH.
Для указания типа заполнителя служат цифро-
вые константы от 0 до 12 или соответствующие им
символические константы (EmptyFill = О, SolidFil 1 = 1,
LineFill = 2 и т. д.). Константа UserFill = 12 позво-
ляет вводить тип заполнителя, определяемый пользо-
вателем.
Для указания стиля линии можно применить цифровые
константы от 0 до 4 или соответствующие им символиче-
ские константы (SolidLn = 0, DottedLn= 1, CenterLn=2,
DashedrLn = 3, UserBitLn = 4). Константа UserBitLn ука-
зывает на то, что тип линии задается программистом. Тол-
щина выводимых линий определяется константами
NormWidth= 1 (нормальная) и ThickWidth = 3 (утол-
щенная) .
Для указания типа текстовых шрифтов используются
цифровые константы от 0 до 4 или соответствующие им
символические константы (TriplexFont= 1, SmallFont =
= 2, SansSerifFont= 3, GothicFont= 4). Направление
текста задается с помощью констант: HorizDir=0 (го-
ризонтальное) и VertDir= 1 (вертикальное). Размер
символа, устанавливаемый пользователем, задается кон-
стантой UserCharSize= 0. Для выравнивания текста
определены следующие константы: 0 — относительно ле-
вого края (LeftText) или нижней границы (BottomText);
1 — относительно центра (CenterText); 2 — относительно
правого края (RigthText) или верхней границы (Top-
Text) .
Для задания операций с точками при совмещении
различных изображений введены константы: NormPut =
= 0 или CopyPut=0 — для простого перемещения изо-
бражения; XorPut= 1 — наложение с выполнением опе-
рации Исключающее ИЛИ; OrPut=2 — наложение с вы-
полнением операции ИЛИ; AndPut=3 — наложение с вы-
полнением операции И; NotPut=4 — перемещение инвер-
тированного изображения.
Определены также логические константы для задания
параметров графического окна: ClipOn=true (отсечение
изображения за пределами графического окна) и
ClipOff = false (изображение не отсекается).
Логические константы TopOn=true и TopOff= false
используются в графической процедуре Bar3D для мани-
пуляций с верхней гранью параллелепипеда.
377
В библиотечном модуле GRAPH описаны также следу-
ющие типы:
LineSettiaBsType - гесого
LineStyle word’.
Pattern • word:
Thickness • word;
end;
TextSettingsType ; record
Font Hord:
Direction : «ord;
CharSise «ord;
Doris «ord;
Tert Hord;
end;
FillSettingsType - record
Pattern Hord;
Color «ord-
end;
PalleteType - record
Sire • byte;
Colors array[0
PointType - record
X,Y • integer;
end;
Vie«PortType record
xl,yl,12,y2:integer;
Clip • boolean;
end;
ArcCoordsType : record
I,Y,
Istart, Tstart,
lend, Tend - integer-
end;
( параметр» шипи }
( СТИН шии }
( способ получения !
< тоцииа }
( параметры текста }
( «рифт !
( иаправуеиие I
( размер символа }
( выравнивание по горизонтали )
{ выравнивание по вертигахи )
( параметры заполнении )
( наполнитель )
( цвет )
( параиетр» текуден палитры )
f число цветов в палитре )
HaxColorsJ of shortint;
{ данные о какдои цвете:
HaiColors г 15 )
( координаты точки !
( координаты графического окна )
( координат» угловых точек )
( отсечеиие изображения за преде-
лами окна- true — отсекать,
false - нет )
( параметры дуги )
( координаты центра )
( координаты начала дуги J
( координаты конца дуги )
В целом организация графической системы в языках
ПАСКАЛЬ и СИ во многом одинакова, а наборы графи-
ческих подпрограмм в значительной степени пересекаются.
Перед началом работы в программе на языке СИ
должна быть выполнена инициализация графической си-
стемы, т.е. указаны графический драйвер и режим работы
этого драйвера (graphdriver и graphmode) Имена драйве-
ра и режима задаются в виде констант, определенных в
файле graphics.h. Так, для драйверов введеры константы;
DETECT (или 0) — автоматический выбор драйвера; CGA
(или 1) —для драйвера CGA.BGI и т. п. Режимы работы
задают, например, размер экрана (320X200 точек, 640Х
X 200 точек и т. п.).
Для выполнения инициализации в начале программы
на языке СИ должны появиться строки такого вида:
378
ini gd = DETECT, gm;
initgraph (<&gd, <&gm, ” ”);
Здесь initgraph — библиотечная функция для инициализа-
ции графической системы; ее последнее поле (третий па-
раметр) содержит маршрут для поиска графического
драйвера. Если в этом поле ничего не записано (” ”),
файл с драйвером должны быть на текущем диске.
Для перехода к текстовому режиму используются
функции closegraph и restorecrtmode. Обе они не имеют
параметров. В случае выбора первой функции для возвра-
та в графический режим необходима повторная инициа-
лизация, т. е. использование подпрограммы initgraph. Если
же выбрана вторая функция, такой возврат можно осу-
ществить с помощью библиотечной функции setgraphmode,
единственным параметром которой является номер ре-
жима.
Для адаптера CGA номера 0,...,3 задают режим экрана
320Х 200 точек с различными цветовыми палитрами, номер
4 определяет режим 640X200 точек. Если используется
адаптер EGA, цифры 0 и 1 соответственно назначают
режимы: 640X200 точек (16 цветов, 4 страницы) и 640Х
Х350 точек (16 цветов, 2 страницы). В случае адаптера
VGA номера 0, 1, 2 означают: 640X200 точек (16 цветов,
4 страницы); 640X350 точек (16 цветов, 2 страницы);
640X480 точек (16 цветов, 1 страница).
Инициализация графической системы в языке
ПАСКАЛЬ производится с помощью стандартной проце-
дуры I nit Grap h (gd, gm, ’ ’);. Здесь gd и gm — переменные
типа integer, которые определяют соответственно графи-
ческий драйвер и режим его работы. Переменная gd может
принимать значения констант, объявленных в библиотеч-
ном разделе GRAPH и предполагающих использование
того или иного драйвера: detect=O, CGA=1, MCGA=2,
EGA=3 и т. д.
Если значение gd не равно нулю, оно используется
в качестве номера драйвера, который загружается в па-
мять, и система переводится в графический режим, соот-
ветствующий второму параметру — gm.
Если перед использованием процедуры InitGraph
переменной gd присвоить значение 0 (или DETECT),
определение требуемого драйвера производится автомати-
чески. При этом вызывается библиотечная процедура
DetectGraph, которая определяет, какие графический
драйвер и режим должны использоваться имеющимся
графическим адаптером.
379
Третьим параметром в процедуре InitGraph является
строка символов (тип string), указывающая маршрут
поиска программы драйвера на диске (пустая строка (’ ’)
предполагает использование текущего директория).
11.2. ПОДПРОГРАММЫ ДЛЯ ПОЛУЧЕНИЯ
ИЗОБРАЖЕНИЯ НА ЭКРАНЕ
Ниже приводятся графические функции языка СИ
для получения изображения на экране дисплея. Сначала
дается содержательное описание функции, затем —необ-
ходимая информация об ее использовании. Сокращения
вида х (объект), у (объект) указывают на смещение объек-
та (например, центра окружности) по горизонтали вправо
(х) и по вертикали вниз (у). Напомним, что угловые
величины задаются в градусах. Если дополнительно не
указан тип параметров, переменные должны иметь целые
значения:
аге (х центра, у центра, угол начала, угол конца, ради-
ус) — вычерчивает дугу; соответствующие углы отсчиты-
ваются против направления движения часовой стрелки от
линии, проведенной по горизонтали вправо по отношению к
центру окружности;
bar (х левой стороны, у верхней стороны, х правой
стороны, у нижней стороны) — вычерчивает закрашенный
прямоугольник;
bar3d (х левой стороны, у верхней стороны, х правой
стороны, у нижней стороны, глубина, р) — вычерчивает
прямоугольный параллелепипед с закрашенной лицевой
гранью (если р= 1, верхняя грань присутствует; если р=
= 0,— нет);
circle(х центра, у центра, радиус) — вычерчивает ок-
ружность;
cleardevice(void) — очищает графический экран; слово
void в языке СИ указывает на отсутствие параметров;
clearviewport (void) —очищает ранее установленное
окно графического экрана;
drawpoly (число узловых точек, int far m []) — вычер-
чивает многоугольник; здесь m — массив записей, в кото-
рых определены координаты х и у всех узловых точек. На-
пример, массив m для треугольника объявляется так:
struct ху (int х, у;} m [4];. После этого можно задать
координаты четырех точек: т[0].х=10; м[0]. у= 10;
т [ 1 ] .х=30; т [ 1 ] ,у= 20; т [2] ,х=20; т [2]. у=40; т [3].
х= 10; т [3] ,у= 10;. Заметим, что местоположение началь-
ной и конечной точек совпадает. Обращение к функции
380
drawpoly для вычерчивания треугольника будет таким:
drawpoly (4, (int far *)m); здесь far — длинный указа-
тель на массив т;
ellipse (х центра, у центра, угол начала, угол конца,
горизонтальный радиус, вертикальный радиус) — вычер-
чивает эллипс;
fillellipse (х центра, у центра, горизонтальный радиус,
вертикальный радиус) — вычерчивает и заполняет эллипс
с использованием текущего наполнителя (например,
штриховка, заполнение точками и т. п.);
fillpoly (число узловых точек, int far m []) — вычер-
чивает и заполняет текущим наполнителем многоуголь-
ник (параметр m определяется так же, как и для функции
drawpoly);
floodfill (х, у, р) — заполняет установленным ранее
наполнителем область экрана, в которую попадает точка с
координатами х, у (здесь р — номер цвета линий, ограни-
чивающих эту область, до которых осуществляется запол-
нение) ;
line (х начала, у начала, х конца, у конца) — вычерчи-
вает линию;
linerel(x приращения, у приращения) —вычерчивает
линию из текущей точки по заданным приращениям;
lineto (х, у) — вычерчивает линию из текущей точки
в точку с заданными абсолютными координатами х, у;
moverel (х приращения, у приращения) — невидимо
перемещает указатель текущей позиции в новую точку по
заданным приращениям;
moveto(x, у) — невидимо перемещает указатель теку-
щей позиции в новую точку с заданными абсолютными
координатами х, у;
outtext (char far *ts) — выводит на экран дисплея
текстовую строку, на которую указывает ts. Например,
вызов функции вида outtext(”GOOD-BYE”); приведет к
выводу на экран строки GOOD-BYE, начиная с текущей
точки. То же самое можно получить, если в программе
использовать следующее объявление и вызов функции:
char ts[] = ’’GOOD-BYE”; outtext(ts);
outtextxy(x, y, char far *ts) — выводит на экран дисп-
лея текстовую строку, на которую указывает ts (здесь х,
у — координаты, определяющие.местоположение на экра-
не выводимой строки);
pieslice (х центра, у центра, угол начала, угол конца,
радиус) — вычерчивает сектор круга;
putimage(x левой границы, у верхней границы, void
381
far *bm, операция) — выводит сохраненное графическое
изображение в окне экрана; здесь bm — указатель на
область памяти, где хранится графическое изображение
(см. функцию getimage; операция — это константа (ее
значения даны выше), определяющая способ наложения
выводимого окна на другое изображение экрана (простое
копирование, инверсия, операция ИЛИ и т. п.). Указатель
bm можно объявить, например, так: void *bm;. Сохранение
изображения в окне размером 100X100 точек от начала
экрана осуществляется следующим образом: int s; s=
= imagesize(0, 0, 100, 100); bm= malloc(s); getimage
(0, 0, 100, 100, bm); здесь s — объем буфера для изобра-
жения; malloc — библиотечная функция языка СИ для
выделения памяти объемом s байт; графические функции
imagesize и getimage будут описаны в § 1 1.4. Для вывода
сохраненного изображения в правом нижнем углу экрана
размером 640X200 точек производится следующий вызов:
putimage (540, 100, bm, 0); здесь последний параметр
(нуль) указывает на необходимость простого копиро-
вания;
putpixel (х, у, цвет) — отображает точку с заданным
цветом по координатам х, у;
rectangle (х левой стороны, у верхней стороны, х правой
стороны, у нижней стороны) — вычерчивает прямоуголь-
ник;
sector (х центра, у центра, угол начала, угол конца, го-
ризонтальный радиус, вертикальный радиус) — вычерчи-
вает и заполняет сектор с использованием текущего
наполнителя.
Набор процедур языка ПАСКАЛЬ для получения изо-
бражения на экране полностью повторяет перечисленные
выше функции языка СИ, соответствующие процедуры в
ПАСКАЛе имеют те же имена и аналогичное назначение
параметров, выполняемые ими действия не отличаются
от описанных выше, поэтому мы не станем йеречислять
их еще раз, а отметим лишь те незначительные отли-
чия, которые имеют место.
Прежде всего напомним, что система программирова-
ния ТУРБО ПАСКАЛЬ одинаково воспринимает строчные
и прописные буквы в идентификаторах. Следовательно,
имена процедур, функций, типов, переменных можно на-
бирать, используя как верхний, так и нижний регистры.
Например, идентификаторы arc, ARC либо Аге будут обо-
значать один и тот же объект в программе, в то время как
в языке СИ они считаются различными.
382
Последний параметр процедуры Bar3D р имеет логиче-
ский тип (BOOLEAN), т. е. может принимать одно из двух
значений — TRUE или FALSE. Если p=TRUE, верхняя
грань параллелепипеда присутствует, в противном случае
(р = FALSE) он выводится без верхней грани.
Для определения координат узловых точек многоуголь-
ника в процедурах drawpoly и fillpoly можно использо-
вать массив записей типа PointType либо соответ-
ствующую типизированную константу. Так, для примера,
приведенного выше при описании функции DrawPoly,
можно определить константу такого вида:
const m:array [1..4] of PoinType =
((\:10; y:10), (x:30; y:20), (x:20; y:40), (x:10; y:10));
Тогда обращение к процедуре для вычерчивания заданно-
го треугольника будет иметь вид DrawPoly (4,m);
В процедурах OutText и OutTextXY параметр, опреде-
ляющий выводимую на экран строку, имеет строковый тип
(string).
В процедуре Putlmage третий параметр bm имеет
тип POINTER и представляет собой указатель на область
памяти, где хранится графическое изображение. Сохране-
ние в памяти изображения в окне размером ЮОХ ЮО
точек от начала экрана выполняют следующие операторы:
s: = ImageSize(O, 0, 100, 100); GetMem(bm,s); Getlmage
(0, 0, 100, 100, bm);. Воспроизведение этого изображения
в правом нижнем углу экрана реализует процедура
Putlmage(540, 100, bm, 0);.
' Ниже приведен первый пример программы на языке СИ:
•include (graphics.h> /» крккер 1 */
ain(}
f int gd:MTJCT, ga, i;
/< запись jii опредехепяи xoopginat ккогоугмькрха «/
strnct [ int 1,1; ! a[6);
/< опредеяеиие хоордкиаг ииогоугмьлка «/
»[0).r.l5; »[0).»=102;
я[1).х:40; »[l).»-90,
a[2}.x-90; »[2).y:90;
i[3).x:115; a[3J.y=I02;
Ж[4].х=65; i[4).y=115;
i[5).x=15; i[5).y=102;
puts("Введвте иокер реккка (0 - 4)'),-
scaaffEd’.Ai);
/« inimansagii графическом састеин «/
initgraph(4gd,4go,");
/» установка кокера репка (ддя драйвера CGA: 0-3 -
320x200 точек, 4 - 640x200 точек; дхя драйвера EGA:
383
(I - 640i200 точек, 1 - 640x350 точек) »/
setgraph«ode(i);
/» 1) янчерчиваиие дуги; ♦/
arc(55,50,0,130,(0);
/« 2} вычерчивание закрадениого прямоугольника </
bar(130,25,230,75);
/< 3) вячерчвваиие прайсу годного параллелепипеда е
закракеииой лицевой граны (р=1) »/
bar3d(200,25,355,75,20,1);
/а 1) вачерчиваияе прайсугодьиого дараллелепипеда е
закратеивой дкцевой граны (р=0; будет отсут-
ствовать верхнаа грань) »/
ЬагЗ<К(10,25,«5,75,20,0);
/» 5) вичерчиваине окрукиоети »/
с1гс1е(575,50,40);
/» 6) вычерчивание многоугольника, координата условии
точек которого определена в массиве 1 »/
drawpoly(6,(int far *)в);
/» 7) вычерчивание эллипса »/
ellipseflOO,105,0,360,50,15);
/> 8) вычерчиваиае закрааеииого эллипса </
Ш1е111рае(317,105,10,20),
/» определение координат треугольника »/
а[0).х=410; »[0).у-102;
[!).х=500; >[1).у=90;
|[2). 1=500; »[2).у=115;
а[3).х=410; а[3).у=102;
/» 0) вычерчивание закраиеииото треугольника »/
f11 Ipoly(4,(int far *));
/» 10) вичерчиваине окружности »/
circle(575,103,12);
/> заполнение вычерченной скрукиссти наполнителей »/
flcodfill(575,103,15);
/» 11) вычерчивание линии »/
11ае(15,140,100,155);
/> 12) переиедеине указатели текудей позиция »/
aovetof120,140);
/» 13) вичерчиваине линии пс относительный координатам »/
linere1(80,20);
/» 14) переиедеине указателя текудей позиции пс
относительным коордииатаи а/
aoverel( 40,-20):
/I 15) вычерчивание линии »/
1 ineto(375,160);
/» 16) перемедеиие указателя и вывод текста - г Книск »/
aoverel(20,-20); и;
outteitfr. Книск');
/» 17) выпод текста -- Кафедра Э В К */
outteztxy(500,150,"Кафедра Э В И');
/» 18) вычерчивание точки зеленого цвета (признак 2) Д/
putpixel(35, 180,2);
/» 13) вычерчивание закранеииого сектора круга »/
pieslice(90,170,335 ,355,100);
/» 20) вычерчняание прямоугольника I/
rectanele(220,180,360,199);
/» 21) вычерчивание закранеииого сектора эллипса V
sector(500,200,20,160,120,30);
/» приостановка выполнения програииы дс накатин клавиии «/
getchO;
/» слЕДУащая часть программы для адаптЕга, ймеяшего еесколь-
384
КО СТРАНИЦ ПЙИЯТП (ДЛЯ АДЙПТЕРЙ CGA ЕЕ СЛЕДУЕТ УДЙЛВТЬ) »/
/I устаионеа актияиой страница с иомерон 1 »/
setactivepage(1);
/I запись изобрагеш i «ояув ашниц страницу Ч
forf i-'O; i<=15; itt)
( setcolor(i); circle(320,100,i*6); }
/» усгаимка апшой страница с ноиерои 0 »/
setactivepage(O);
/' сиена изобракеиий иа экране i гооттетстш с ионерон
поденной активной страница »/
do (
outtextxy(50,0,"Введите иомер актияиой страница*
" (0 иди 1); 2 -- занернение работа*);
scanf(*Xd“,4i);
/» нннод иа экран изображения из страница с номером i »/
setvisualpage(i); }
nhile(i!:2);
closegraph(); /» заяердеиие работа с графикой »/ )
После запуска программы на выполнение на экране дисплея
появится сообщение:
' Введите номер режима (О—4)
Возможные номера режимов для адаптера CGA, EGA или VGA даны
выше. Если ввести цифру 1, будет задано: разрешающая способность
экрана 64ОХ35О точек; 16 цветов; 2 страницы. В программе даны
подробные поясняющие комментарии. В конце идет фрагмент для работы
со страницами экрана. Для этого используются функции setactivepage
(установка активной страницы) и setvisualpage (установка видимой
на экране страницы).
Многие графические адаптеры, например EGA и VGA, в опреде-
ленных режимах работы имеют встроенную память для хранения
нескольких образов экрана (см. гл. 2). Один такой образ называется
страницей. По умолчанию, активизируется страница с номером 0, и она
же отображается на экране. Функция вида setactivepage(1); активи-
зирует страницу с номером 1. Теперь в нее будут заноситься создаваемые
графические образы, однако они не будут видны на экране. Чтобы
сделать первую страницу видимой, необходимо вызвать функцию
setvisualpage( 1)Изменяя значение аргумента этой функции, можно
мгновенно обновлять содержимое экрана, просматривая различные
страницы.
Вывод русских букв на экран дисплея возможен только в том
случае, если предварительно через вектор прерывания 31 создан соот-
ветствующий генератор знаков.
Вторая программа на языке СИ строит на экране дисплея три
вложенные окружности белого, зеленого и голубого цветов (функция
setcolor для установки цвета будет описана в следующей главе). Затем
изображение левого верхнего угла экрана размером 1ООХ 100 точек
сохраняется в файле ecran.f, который создается на текущем диске:
•include <stdio.h> /» прниер 2 «/
•include <«lloc.h>
•include <grnphic3.h>
lain!)
{ fits *fopen(), *fp;
int gd^DKTKCT, 81, a, i;
/« обшденне фдикцнн aalloc jii дннаинчесдого
iijeieni nanti */
void »ialloc();
13 Скляров в. A.
385
/У bi - указатеиь иа Syfep ди coipaiem кзобраденкя </
arraigned char *hi;
initgraph(Jgd,Jgi,");
circlet 100,100,50);
setcolor(2);
circlet 100,100,30);
setcolor(3);
circle(100,100,10);
/» открктие файда ecran.f ди aanei ('и') У/
fp=fopeaCecraa.f,"»');
/< опредедене обгеиа буфера (в байтав) дхя изображения </
з=1м{ез!ае( 0, 0,100, 100);
/у выдехеиие иаияти объеиои з байт </
hi=ialloc(s);
/< совраиеыие изобракеиия разиерои ЮОяЮО точек в
буфере, иа историй указывает hi у/
getiiaget0,0,100,100,hl);
/< запись азобракеиии из буфера а файд ecran.f У/
for (i:0;i(s;it*)
fprintf(fp,"Xi ‘.«(hiH));
/* закрытие файда ecraa.f */
fclose(fp);
closegraphf);
1
Заметим, что в файле ecran.f сохранится только четверть окружно-
сти.
Третья программа на языке СИ считывает изображение с диска
из ранее построенного файла и выводит его на экран дисплея в окне,
левый верхний угол которого имеет координаты (1ОО, 1ОО):
liaclade (alloc.h> /I пример 3 У/
linclude (graphics.h>
liaclade (stdio.h)
laiat)
( FILE yfopeal), *fp;
iat gd-BETECTj gn, s, i;
void Уаа11ос();
unsigned chat aba;
iaitgraph(Jgd,3ga,");
/У открытие Файда ecran.f ди чтении ("г") У/
fp-fopeafecraa.f ,"r");
s-' iaages 1ге( 100, 100,200,200);
hpnal loot s);
/У чтеаие совраиеипого ранее изобрахеиия из файда
ecraa.f У/ '
fat(к 0;i(s;itt)
fscaaf (fp, ’Xi’, bmi);
ft закрытие файла ecraa.f У/
fclose(fp);
/у вывод изобракеиия из буфера, иа который указывает Ьи,
я область экрана с координатами (100.100). Операция 0
задает простое копирование изобрахения */
putiaaget 100,100,bm,0);
closegrapht);
Последний параметр функции putimage задает операцию с изобра-
жением. Например, если О поменять на 4, изображение будет проинвер-
386
тировано. Операндами для двухместных операций И, ИЛИ, Исключаю-
щее ИЛИ являются одноименные точки изображения, которое уже
есть на экране, и точки нового изображения, возникающего в результате
выполнения функции putimage. Так, если задана операция И, фигуры
на экране будут возникать только там, где точки нового и старого
изображений совпадут.
11.3. ПОДПРОГРАММЫ ДЛЯ УСТАНОВКИ
ПАРАМЕТРОВ ИЗОБРАЖЕНИЯ
Перечислим графические функции языка СИ для уста-
новки параметров изображения на экране дисплея:
graphdefaults (void) —сбрасывает все графические
установки в первоначальное состояние, заданное по умол-
чанию;
setactivepage (номер страницы) — устанавливает ак-
тивную страницу экранной памяти, в которую будет
осуществляться запись графического образа экрана;
setalIpalette (struct palettetype far *p) — устанавли-
вает все цвета текущей палитры. Использование этой
функции рассмотрим на примере адаптера EGA. Палит-
ра — это набор возможных цветов, из которых собирается
изображение на экране. Адаптер EGA позволяет одновре-
менно отображать 16 различных цветов, информация о ко-
торых хранится в 16 регистрах. Старшие два разряда
каждого регистра не используются, а другим разрядам
(с 5-го по 0-й) соответствуют буквы rgbRGB. Строчные
буквы задают 1 /3 интенсивности красного, зеленого и си-
него лучей электронно-лучевой трубки, а прописные — 2/3
их интенсивности. Таким образом, если в некоторый
регистр записать число 20(101002), то биты соответствую-
щего двоичного числа зададут буквы g (светло-зеленый) и
R (красный). Наложение указанных цветов дает новый
цвет (коричневый). Шесть разрядов (rgbRGB) одного
регистра позволяют задать 26=64 разных цвета. Шестнад-
цать регистров задают совокупность цветов в одной па-
литре. Различные комбинации из 64 по 16 цветов образуют
возможные палитры. Функция setal 1 palette позволяет вы-
брать одну из них. Каждому регистру соответствует
элемент массива colors в записи *р (см. также § 11.1).
Занесение числа в этот элемент — то же самое, что его
запись в регистр. Тогда, если некоторый элемент имеет
значение 20, то он задает в палитре коричневый цвет.
Пусть в программе задано объявление struct palettetype
pal;. Тогда обращение к рассматриваемой функции
будет setalIpalette (&pal);, а запись информации, напри-
мер, о красном цвете в массив colorsrp.colors [j] =4;,
387
где 0^j^l5 (значение j задает номер регистра EGA);
setaspectratio (х, у) — устанавливает масштабные
коэффициенты по горизонтальной (х) и вертикальной (у)
осям. Это необходимо для того, чтобы задать правильную
форму кривых типа окружностей и дуг (на экране дисплея
горизонтальные и вертикальные линии, содержащие оди-
наковое число точек, могут иметь неодинаковую длину).
По умолчанию, задано у= 10000. Для построения правиль-
ных фигур следует выбирать х= 10000, если элементарная
точка является квадратом, и х< 10000, если она вытянута
по вертикальной оси;
setbkcolor (номер цвета) — устанавливает цвет фона;
setcolor (номер цвета) — устанавливает цвет графиче-
ских образов;
setfillpattern (char far *up, номер цвета) — устанавли-
вает заданный пользователем наполнитель экрана; здесь
up — указатель на область памяти, в которой определена
конфигурация элемента заполнения в формате 8X8 точек
(8 байт). Предположим, что мы хотим использовать
наполнитель, базовый элемент которого показан на рис.
11.1. Этот элемент изображен в стандартной матрице
Веса битовых разрядов для 1-й и 2-й
шестнадцатеричных цифр
размером 8X8 точек. Каждой строке матрицы сооответ-
ствует двухразрядное шестнадцатеричное число. Его пер-
вая цифра представляет двоичное число левой половины
строки матрицы, а вторая цифра — двоичное число правой
половины. После этого должен быть объявлен следующий
массив р: char р [] ={(0x10, 0x28, 0x7с, Охаа, 0x7с, 0x28,
0x10, 0x00};. Здесь первые две цифры Ох (нуль икс) говорят
о том, что соответствующее число шестнадцатеричное.
388
Вызов функции setfillpattern для выбранного наполнителя
и задание для него красного цвета будут осуществлены
так: setfillpattern (р,4);
setfillstyle (номер наполнителя, номер цвета) —уста-
навливает стиль наполнителя. Номер наполнителя может
изменяться от 0 до 12 (см. § 1 1.5). Последняя цифра (12)
указывает, что наполнитель будет задан пользователем;
setgraphbufsize (беззнаковое целое число — размер бу-
фера) — изменяет размер внешнего графического буфера;
может быть вызвана перед функцией initgraph; возвраща-
ет предыдущее значение объема внешнего буфера;
setgraphmode (номер режима) — устанавливает ре-
жим работы графического адаптера;
setlinestyle (стиль линии, образец битового базового
отрезка, толщина) — устанавливает стиль линии, который
может быть таким: непрерывная линия (0); линия из
точек (1); штриховые линии (2 и 3), при этом второй
параметр принимает нулевое значение. Если же задать
стиль 4, то вид линии пользователь конструирует из
примитивных отрезков длиной 16 точек. Расположение
точек задается битовым представлением беззнакового це-
лого числа, являющегося вторым параметром функции.
Например, если задать число 255 (FFie), его битовое
представление будет такое: 0000000011111111. Другое
число 65280 (FFOOie) дает следующий результат:
1111111100000000. Таким образом, в первом случае будут
чередоваться прочерки и штрихи, а во втором — штрихи
и прочерки. Если задать шестнадцатеричное число
ОхСССС с битовым образом 1100110011001100, то прими-
тивный отрезок будет включать 4 штриха и четыре прочер-
ка из двух точек каждый. Линия может быть нормальной
(0 в третьем параметре) и толстой (3);
setpalette (старый номер, новый номер) —изменяет в
текущей палитре один цвет на другой по их номерам;
settextjustify(по горизонтали, по вертикали) —уста-
навливает выравнивание текста; каждый параметр может
принимать значения от 0 до 2;
settextstyle (шрифт, направление, размер символа) —
устанавливает стиль текста. Параметр «шрифт» может
принимать значения от 0 до 4 (см. § 11.1), из них только
первое не требует загрузки новых генераторов знаков
(файлы *.CHR). Второй параметр имеет значения: 0 —
для горизонтального, 1 — для вертикального направления
текста. Размер символа — это цифра, показывающая, во
сколько раз увеличивается его величина. Если эта цифра
389
нуль, размер задается пользователем с помощью функции
setusercharsize;
setusercharsize (mx, dx, my, dy) — пользователь уста-
навливает размер символа (изменение по горизонтали в
mx/dx раз и по вертикали в ту/dy раз). В случае измене-
ния размера параметр «шрифт» в предыдущей функции не
должен принимать значение 0;
setusercharsize (мх, dx, my, dy) — пользователь уста-
вой границы, у нижней границы, р) — устанавливает
размер окна экрана для вывода изображения (если
р= — 1, то с отсечением изображения за пределами окна;
если р = 0, без отсечения);
setvisualpage (номер страницы) — устанавливает
страницу, содержимое которой отображается на экране
дисплея;
setwritemode(HOMep режима) — устанавливает режим
вычерчивания линий: если номер режима 0, новые линии
«накладываются» на старое изображение; если же этот
номер 1, между точками новой линии и имеющимся на
экране изображением выполняется операция Исключаю-
щее ИЛИ. Напомним, что эта операция дает истинный
результат, если по выбранным координатам точка есть
хотя бы в одном изображении, но не в обоих вместе. Истин-
ность результата приводит к сохранению старой либо появ-
лению новой точки на экране.
Все перечисленные выше функции СИ для установки
параметров изображения имеют одноименные аналоги в
языке ПАСКАЛЬ. Описанные в предыдущей главе под-
программы можно использовать без изменения с учетом
следующих замечаний: указатель на запись типа struct
palette far *р в процедуре setalIpalette заменяется перемен-
ной типа Palette Туре, описание которого было приведено
в § 11.1; первый параметр процедуры SetFil 1 Pattern имеет
тип FillPatternType, который определен в разделе библио-
теки GRAPH как array [1..8] of byte и задает конфигура-
цию элемента заполнения; последний параметр в процеду-
ре SetViewPort р имеет логический тип (BOOLEAN) и
задает отсечение изображения за пределами графического
окна при p=TRUE.
Рассмотрим программу на языке СИ, использующую различные
функции для установки параметров изображения:
linclude (graphics h> /* пример 4 */
«ain()
[ int gd=BETECT. ga, i;
/» задание иапошдеди подьзояатедем »/
char J-[0x10,0x20,0x7c.0zaa.0z7c,0x20,0x10,0x00);
initgraphfigd,tg>,"");
390
/» яызод верного праиоугошика »/
rectangle(100,100,300,170);
/» вынод окрухиости »/
circlet 100,100.50)
/» установка хаситабиак коэффициентов по горизонтальной
и вертикальной оснн »/
setaspectratio(3,2);
/» вывод той ле окружности с установленными наснтабинни
коэффициентами »/
circle(100,100,50);
/» изменение цвета фона приблизительно через 1 секунду »/
for(i-0;i<:15;I++) ( setbkcolor(i); delay(lOOO); )
/* нняод емедеиных прайсугольиикоа и охраненных i
разине цвета »/
for(i:0;icl5;iH) ( setcolor(i);
rectaagle(400e2»i,00y24i,550y2»i,160y2*i); )
delay( 1000 j; /» задержка на 1 секунду »/
/» установка зеленого цвета фона; задержка иа 1 секунду »/
setbkcolor(2); delay(lOOO);
/» усшояка наполнители жрасного цвета (4), заданного
пользователем (см. массив р(]) »/
setfillpattera(p,4);
/» заполнение правой части первого прнмоугольиика задан-
ным пользователем наполнителем (см. массив р(]) »/
floodfill( 150,150, 15);
/» установка наполнителя из точек (9) синего цвета (1) »/
selfillsty Le(9,1);
/I заполнение последнего прнмоугольиика »/
floodfill(500,160,15);
/* уста.чмка толстой линии (3), заданной пользователей »/
set 1inesty1е(4,255,3 );
/» вачерчиваиие шин с установленным стилен »/
11ае(200,20,600,20);
/» теперь втрихи к промежутки в зиими поменнвтся местами */
setlinesty1е(4,65200,3);
/* начерчивание линии с новым установленным сталей к/
Нае(200,25,600,25);
/» вычерчивание друг под другом четыре! тонких линий (1)
с различными стандартными стилаив </
for(i-0;i<4;itt) ( setlinestyle(1,0,1;;
liae(200,35y5»i,600,35e5»i); J
/» установка варавииваиии текста относительно левого края
по горизонтали к центра по вертикали */
settextjustify(0,1);
/» внвод текста "Инкский радиотехнический институт" »/
outtextxy(270,70,"Иниский радиотехнический институт');
/» установка стили текста: «рифт стандартный (0); направ-
ление вертикальное (1); размер удвоенный (2) «/
settextstylef0,1.2);
outtextsy(340,140,'Кафедра");
mttextxy(370,140,’3 В И');
delay)1000); /» задержка иа 1 секунду »/
/» установка окиа размером 100x40 »/
set ie«port(455,135,555,175,-1);
clearviewport(); /» очинка окиа »/
/» заполнение окиа желтыми точками (иа зеленом фоне) »/
self 111 style!10,14);
floodfill(10,10,15);
/* угтаиоика сиреневого цвета (5) »/
setcolorl5);
391
/» янравнннаиме по центру «7
settextjustify(1,1);
/» установка ди выводимых символов иасвтабннх ииохитехея:
4/5 - по горизонтальной оси; 3/2 - по вертикальной оси »/
setasercharsixel4,5,3,2);
/» текст TRIPLEX-FONT (I); направление горизонтальное (0);
разиер задается пользователей (0) »/
settextstyle(I,0,0);
/» сииволн будут ииеть сиреневый цвет »/
oattextxy(50,14,"25");
closegraphl);
)
Все, что необходимо для понимания приведенной программы, рас-
смотрено выше. После ее запуска на экране появятся прямоугольник
и окружность. Затем функция setaspectratio изменяет масштабные
коэффициенты по горизонтальной и вертикальной осям. В результате
вторая окружность будет иметь форму овала. Далее демонстрируются
изменения цвета фона, заполнение части прямоугольника наполнителем,
показанным на рис. 11.1, а также другие действия, указанные в
содержательных комментариях,
В следующем примере (язык СИ) показаны унарные (простое
копирование, инверсия) и бинарные (И, ИЛИ, Исключающее ИЛИ)
операции над изображениями:
•include <stdio.h> /» пример 5 »/
•include (graphics.h>
•nisi)
( ht gd=BETECT, gi,n,i;
void »Mlloc(), »buf; char «text;
initgrnph(4gd,4g»,"); for)1=0;i<=4;1H)(
rectangle)300,40,340,00); /« верней ирииоугохни «/
rectangle)310,140,330,100); /« «ихней праиоугохьввк «/
s= ieiagenize(290,130,3 50,200); baf=aalloc(n);
/« сохранение изображения с иней пряиоугольеекои в
буфере, на который указывает baf «/ .
getinnge(290,130,350,200,baf);
/« установка ввравиивааии по цемтру выводимого текста «/
settextjantify)1,1); delay(2000);
/« выбор текста для внаомцеиой операцне в pntiaage »/
nnitch(i)
( case 0: texfc’apocroe коаироваеее"; break;
case 1: 1ех1='операции Вскичаццее ВДВ";break; e'
case 2: 1ех1="оаерация ВДВ"; break;
cane 3: text="операций В"; break;
case 4: 1ех1="ииверсии изобраденм"; break; )
/« отобрахение текста о выполняемой операции «/
oattextxy(320,5,text);
/« вивод сохраненного изобрахеняя с операцией 1 «/
patieage(290,30,baf,i); delay(2000) ;
cleardevice)); /« очистка экрана »/ )
onttextxy(320,5, Вскичаицее ВДВ );
/« Установка операции Искичацее ВДВ »/
setarite«ode(l);
rectangle)300,00,340,120);
rectangle(310,00,330,120); delay (2000);
cleardevice();/« очистка экрана »/
oattextxy(320,5,"Сброс операции Вскмчаицее ВДВ');
392
/t Сброс операцви Векичакдее НЛН I/
netwriteeode(0); recta ngle(300,00,340,120);
rectangle(310,00,330,120); delay(2000);
closegraphf); )
Сначала друг под другом строятся два прямоугольника. Затем
фрагмент с нижним прямоугольником запоминается в буфере, на кото-
рый указывает buf. После этого он начинает накладываться с исполь-
зованием различных логических операций на фрагмент с верхним прямо-
угольником. В верхней части экрана отображается текстовая информация
о выполняемой операции. Смена различных изображений производится
через 2 с (delay (2000). Далее демонстрируется функция setwritemode.
По умолчанию, установлен нулевой режим, и новое изображение на-
кладывается на старое (так же, как и при операции ИЛИ). Если задать
первый режим, наложение выполняется с использованием операции
Исключающее ИЛИ (общие линии разных изображений будут пропа-
дать).
Следующая программа (язык СИ) демонстрирует построение функ-
ции вывода gprintf для графического режима:
linclude <stdio.h> /I прииер 6 »/
linclude (graphics.h>
linclude (stdarg.h) /I для va - функций I/
/I иротот функции еавода ди графяческого репка I/
void gprintffint zl.int yl.char If,,,,);
aint)
( int gd-DETECT,gii,a,h,k;
pats("Hac«Ta6»H# коэффициент?");
scant fid' ,4k);
initgraph(4gd,4gu,");
settextjustify(1,1);
gprintf(320,100,"Введвте через пробед два целая чнсха');
scanf("kdkd",4а,4b);
cleardevicef); /I очистка экрана »/
setcolor(2); /I установка зеленого цвета I/
settextstyle(0,0,k);
gprintf(320,50,"Xd t kd - *d’,a,b,nfb);
setcolor(3); /» установи краевого цвета »/
gprintf(320,100,"ltd - id : kd",a,b,u-b);
setcolor(d); /I установка голубого цв'та I/
gprintf(320,150,"kd I kd - Xd",a,h,a*b);
/» возврат к исходной установке всех параиетров I/
graphdefaults();
gprintf(0,0,"Конец работа графической сиетеиа");
delay(2000);
closegrapho; ) /» конец преградив main I/
/» фшци вывода для грйфичесюого решйI/
void gprintf(int xl,int yl,char If,,,.)
( va_llst ар; /I для фуикцяи vsprintf I/
char str(81); /I буфер для строки I/
va^etart(ap,for»at); /I для функции vsprintf I/
vsprintf(str,f,ap); /I завись текста в строку str в
соответствии с фориатои f I/
outtextxy(xl,yl,str);/I вавод содерхииого строки I/
va_end(ap); ) /I дли функции vsprintf I/
Сначала необходимо ввести масштабный коэффициент (целое
число), показывающий, во сколько раз надо увеличить размер символа.
Затем вводятся два целых числа, над которыми выполняются операции
393
сложения, вычитания и умножения. Полученные результаты выводятся
на экран в графической форме, Так, если ввести 6 и 8, то друг под другом
отображаются строки: 6+8= 14; 6—8 = — 2; 6*8=48. Для них установле-
но выравнивание по центру текста. Функция gprintf является аналогом
printf, но предназначена для графического режима. В ней широко
использованы va-функции, определенные в файле stdarg.h.
11.4. ПОДПРОГРАММЫ ДЛЯ ПОЛУЧЕНИЯ
ПАРАМЕТРОВ ИЗОБРАЖЕНИЯ
Перечислим графические функции языка СИ для опре-
деления параметров изображения:
detectgraph (int far *gd, int far *gm) — позволяет
определить графический драйвер (*gd) и режим (*gm);
getarccoords (struct arccoordstype far *dug) —дает
значения координат дуги, являющихся элементами запи-
си *dug типа arccoordstype (см. § 11.1);
getaspectratio (int far *х, int far *y) — позволяет полу-
чить коэффициент (у/х) приведения линий по координатам
х и у к одинаковой длине;
getbkcolor (void) — возвращает номер текущего цвета
фона;
getcolor (void) — возвращает номер текущего цвета
линий;
getdrivename (void) — возвращает указатель на стро-
ку с именем текущего графического драйвера;
getfil 1 patterп (char far *up) — позволяет получить бай-
ты для символов, применяемых пользователем при указа-
нии стиля заполнения (параметр up определен в функции
setfillpattern). Например, для символа, представленного
на рис. 11.1, параметр up будет указывать на такую
последовательность байтов: 0x10, 0x28, 0х7С, ОхАА, 0х7С,
0x28, 0x10, 0x0;
getfilIsettings (struct filIsettfingstype far *ff) —дает
значения параметров заполнения цвета экрана»: являю-
щихся элементами записи *ff типа filIsettingstype (см.
§ 11.1);
getgraphmode (void) — возвращает номер режима
отображения графической информации;
getimage (х левой границы, у верхней границы, х правой
границы, у нижней границы, void far *bm) — позволяет
получить и сохранить в области памяти, на которую
указывает bm, окно экрана с заданным размером, Приме-
ры использования этой функции были даны выше;
getlinesettings (struct linesettingstype far *11) —дает
значения параметров линии, являющихся элементами за-
писи *11 типа linesettingstype (см. § 11.1);
394
getmaxcolor (void) — возвращает максимальное число
цветов;
getmaxmode (void) — возвращает наибольший номер
графического режима для текущего .драйвера;
getmaxy (void) — возвращает размер экрана в точках
по горизонтали;
getmaxy (void) — возвращает размер экрана в точках
по вертикали;
getmodename (int m) — возвращает указатель на стро-
ку с именем графического режима по его номеру гл;
getmoderange (int gd, int far *1, int far *h) — возвра-
щает диапазон значений возможных режимов (от *1 до
*h) для драйвера gd;
getpalette (struct palettetype far *p) — позволяет полу-
чить информацию о текущей палитре (см. также § 11.3);
getpalettesize (void) — возвращает число цветов в од-
ной палитре;
getpixel(x, у) — возвращает номер цвета точки с коор-
динатами х, у;
gettextsettings (struct textsettingstype far *tt) — дает
значения параметров текста, являющихся элементами
записи *tt типа textsettingstype (см. § 11.1);
getviewsettings (struct viewporttype far *v) — дает
значения параметров окна, являющихся элементами запи-
си v типа viewporttype (см. § 11.1);
getx (void) — возвращает значение координаты х (в
точках) для указателя текущей позиции;
gety (void) — возвращает значение координаты у (в
точках) для указателя текущей позиции;
grapherrormsg (interror) — возвращает указатель на
строку с наименованием возможной ошибки по ее номеру
error;
graphfreemem (void far *p, unsigned размер памя-
ти) — освобождает блок памяти заданного размера (в
байтах) из области памяти, на которую указывает р;
является аналогом функций free и realloc для графической
библиотеки;
_____graphgetmem (unsigned размер памяти) — выделяет
блок памяти заданного размера (в байтах) и возвращает
указатель на его начало; является аналогом функции
malloc для графической библиотеки;
graphresult (void) — возвращает номер ошибки (целое
число от —14 до —1 и —18); значение нуль говорит об
отсутствии ошибки;
imagesize (х левой границы, у верхней границы, х пра-
395
вой границы, у нижней границы) — возвращает значение
объема буфера (в байтах) для сохранения графической
информации в окне экрана заданного размера; принципы
использования этой функции рассматривались выше;
textheight (char far *t) — возвращает значение высоты
символа (в точках), передаваемого в виде параметра;
textwidth (char far *t) — возвращает значение ширины
символа (в точках), передаваемого в виде параметра.
В ПАСКАЛе графические подпрограммы для установ-
ки параметров изображения имеют те же имена, что и в
языке СИ. Выполняемые ими действия практически
аналогичны. Ниже кратко характеризуются отличия под-
программ в системе программирования ТУРБО ПАСКАЛЬ:
длинные указатели типа int far *gd, int far *gm заменены
переменными целого типа (VAR GD, GM: INTEGER);
вместо указателей на записи (например struct arccoord-
stype far *dug) используются переменные соответствующе-
го типа, описанного выше, в § 11.1 (VAR AR:
ARCCORDSTYPE); если результатом работы подпрограм-
мы является строка, в ПАСКАЛе соответствующая
функция будет иметь тип STRING; аналогов под-
программ __________graphfreemem и______________graphgetmem в ПАСКАЛе
нет.
Рассмотрим программу на языке СИ, использующую различные
функции для получения параметров изображения:
linclude <stdio.h> /X првиер 1 t/
linclude (graphics.h>
>ais()
( int gd^DETECT, ga, x», ya, ko, gp, xa, ya, bkcolor,
color, нс, grxi, an, ix, ay, 1, h, ha, ns;
long xl; void far »ba; unsigned s;
char Xdn, »an, »ge;
struct arccoordstype dug; e,
struct viewporttype v;
iaitgraph(&gd,&ga,"");
aovetot150,200};
x>:getx(); yi=gety(); ko-grnphresult();
setcolor(3); /х установка гохубого цвета х/
arc(320,100,50,260,40}; /X зачерчивание дуги X/
getchO; /X приостановка до иажатия кхазиви х/
getarccoords(&dug); /х похучеиие координат дуги х/
/х соединение хииией иачаха и конца дуги х/
llnefdug.xstart,dug.ystart,dug.xend.dug.yend);
gp-getpixel(dug.xstart,dug.ystart);
/х квадрат без испохьзовании коэффициента ггркведеикя х/
rectaagleffl,0,100,100); delay(500);
getaspectratio(&xa,&ya);
xl:(95b»(long)ya)/(long)xa;
setcolor(6); /х установка коричневого цвета »/
396
/t квадрат посде исподъзования коэффициента приведения »/
rectaag 1е(0,0,(int)xl,95);
setvie«port(0,0,130,130,-1);
s= iaages1ге(0,0,130,130 );
getviexsettings(Sv);
/» выделение иаияти и сохранение в ней фрагмента экрана »/
ba-_graphgetaem(s); getimage(0,0,130,130,ba);
putimage( 500,60,ba, ();
/» освобождение паши и пауза до наития кдавиии »/
_graphfree«e«(b8,s); getch();
restorecrtaode(); /» переход к текстозону редииу »/
printffxa = 3d, ya = Jd, xl : Sd\n",ха,ya,(int)xl);
/« приостановка и переход к графической^ ренину 1 »/
getch(); setgraphaodef1);
bkcolor-getbkcolorf); /» текущий цвет фона »/
colorgetcolor(); /» текущий цвет линий »/
ac-getmaxcolorf); /» иаксииальное число цветов »/
grargetgraphmodef); /» графический редин »/
dn:3,/»getdrivernaae();»/ /» иия текущего драйвера »/
вп-3;/*getaodenaee(1);♦/ /» иия редина с ионерон 1 »/
а»=3;/»getaaxaode();»/ /» наибольший ионер редина »/
axvgetiaxxl); «у=getaaху(); /» разнер экрана »/
get»oderange(gd,Sl,Sh); [t диапазон рединоз »/
hs:t«theightfH"); /» высота буква Н »/
из;textHidthfI"); /» ширина знака ! »/
ge=grapherrorasg(-10); /» ина оиибки с ионерон -10 »/
closegrapht);
/» вывод иифорнации о полученных паранетрах графического
изобрахеиия »/
printf(“цвет фоиа - ХйДшет линий - ЗйДанаксиналь'
'ное число цаетоа - 3d;\пграфнческий рехнх - '
ЗйДпиаибохиий ионер графического редина - "
"ЗйДичисхо точек по горизонтали - ХйДачисхо"
’ точек по аертхкаи - ЗйДииаихеиыий и наиб"
'ольашн иохера режииов - 3d ЗйДвграФический'
' редки с ионерон 1 - Хз;\птекудий графический'
' драйвер - ХзДпцвет точки - ХйДпкоордихатн '
"точки - Xd 3d;\nKoa оиибки - 3d;\nnucota бу'
’кв» Н - 3d;\n»HpHna знака ! - 3d;\nrpa$H4ecs”
'ая оиибка с ионерон -10 - Xn.'.bkcrlor,color,
ис,grx,п,их,иу,1,h,HU,dn,gp,tl,у>,ko,hs,из,ge);
printff\n0K80: слева - 3d; справа - 3d; сверху - 3d; '
'снизу - 3d.',v.left,ч.right,v.top,v.botto»)-,
)
Сначала указатель перемещается в точку (150, 200) и определяются
ее координаты (xm, ут). Потом вычерчивается дуга и линией
соединяются ее начало и конец. Соответствующие координаты опреде-
ляются с помощью функции getarccoords. Далее вычерчивается квадрат
без использования и с использованием коэффициента приведения с
помощью функции getaspectratio. В,первом случае квадрат на экране
будет представлен как прямоугольник, во втором он будет иметь
правильную форму. Применение подпрограмм для получения информации
из полей различных записей продемонстрировано на примере функции
getviewseltings (см. также последнюю функцию printf). Здесь же по-
казано, как выделять (____________graphgetmem) и освобождать (graphfreemem)
память. Наконец, определяются и выводятся на экран дисплея раз-
личные параметры графического изображения.
397
Следующий пример демонстрирует использование функции getfil-
1 patter п:
(include <stdio.b> /» пример 0 »/
(include (graphics.h>
la is()
( 1st gMETSCT,g>,i,j;
cbar cif,p[ 1= (0,0,OxfC,0x44,0x30,0x30,0x44,OxFC);
initgraph(4gd,4gB,""
setfi1 Spatters(p,14); /» xextaO цвет (14) »/
/4 ввдшаме эххипса и его заполнение заданный
иапохиитехеи 4/
fillellipse(320,100,200,50);
/« получение байтов с информацией о шохшехе «/
getfillpattern(p); delay(2000);
closegraph();
/* выгод битовой матрицы дхи введенного «апохвмтехя i
вестнадцатермчянх чисех, соответствующих ее строкам «/
pntsf\t\t матрица за&олпвпи я\в");
for(i:0;i<8;iH) ( printf("иестиадцатерячвое чвсдо '
Х2г; двоачиое чнсдо - ‘,р[Ц);
for (j-7, j>-0; j-)
printfl' J«e',(cif--(p[i]»j)tl,cif),(j-=O)?'\n':' ');
) getch(); )
В качестве наполнителя задан знак 2. Им заполняется площадь
внутри эллипса. Затем выводятся шестнадцатеричные числа для всех
байтов наполнителя и соответствующая битовая матрица. Расположение
единиц в ней будет соответствовать знаку S.
11.5. ОТОБРАЖЕНИЕ ПСЕВДОГРАФИЧЕСКОЙ ИНФОРМАЦИИ
При работе с псевдографической информацией полезны
функции, определенные в файле conio.h (язык СИ). Они
позволяют работать с окнами, имеют средства переме-
щения курсора в нужные позиции и т. п.
Дадим краткую характеристику этих функций:
clreol (void) — стирает строку в окне от позиции кур-
сора до конца; ’
clrscr (void) — стирает информацию в окне;
cgets, cprintf, cputs, cscanf — эти функции подобны
аналогичным функциям gets, printf, puts, scanf, но пред-
назначены для работы с окнами;
delline (void) — стирает в окне строку, содержащую
курсор;
gettext (х слева, у сверху, х справа, у снизу, void
*bm) — позволяет получать и сохранять в области памяти,
на которую указывает bm, окно экрана с заданным раз-
мером; при успешном завершении возвращает ненулевое
значение;
gettextinfo (struct text_info *t) — позволяет получать
398
информацию о текущем текстовом режиме; используемая
запись определена в файле conio.h следующим образом;
struct text__________________info {
unsigned char winleft;
unsigned char wintop;
unsigned char winright,
unsigned char winbottom;
unsigned char attribute;
unsigned char normattr;
unsigned char currmode;
unsigned char screenheight;
unsigned char screenwidth;
unsigned char curx;
unsigned char cury;
/* граница окна слева */
/* граница окна сверху */
/* граница окна справа */
/* граница окна снизу */
/* байт атрибута */
/т нормальный режим */
/ч- режим курсора */
/* высота экрана */
/* ширина экрана */
/* координата х курсора */
/* координата у курсора */
gotoxy (х, у) — перемещает курсор в окне в позицию
(х, у);
highvideo (void) — устанавливает повышенную яркость
свечения выводимых символов;
insline(void) — вставляет линию, т. е. перемещает
строку с курсором и весь соответствующий текст на по-
зицию вниз;
lowvideo(void) — устанавливает пониженную яркость
свечения выводимых символов;
movetext (х слева, у сверху, х справа, у снизу, новая
позиция х слева, новая позиция у сверху) — перемещает
текст из заданной области экрана в новую область, для
которой указаны координаты ее левого верхнего угла (по-
следние два параметра); возвращает ненулевое значение
при успешном завершении;
normvideo(void) — устанавливает нормальную яр-
кость свечения выводимых символов;
putch(sim) — выводит символ sim в окно на экране;
puttext(x слева, у сверху, х справа, у снизу, void
*bm) — выводит текст из области памяти, на которую ука-
зывает bm, в окно с заданными размерами;
textattr(3HaneHHe атрибута) —устанавливает атрибут
выводимых символов; возможные значения различных
атрибутов приведены в гл. 2;
' textbackground (номер цвета) —устанавливает цвет
фона;
textcolor (номер цвета) —устанавливает цвет симво-
лов;
textmode (номер режима) —устанавливает текстовой
режим работы экрана, например: 0—40 знаков, 25 строк;
2—80 знаков, 25 строк; 7 — монохромный режим;
399
wherex (void) — возвращает горизонтальную коорди-
нату позиции курсора в текущем окне;
wherey (void) — возвращает вертикальную координа-
ту позиции курсора в текущем окне;
window(x слева, у сверху, х справа, у снизу) — уста-
навливает окно заданного размера.
Среди других функций в conio.h использованы: getch
(void), возвращающая значение символа с клавиатуры
без эха на дисплей; getche(void) —то же, что и getch,
но с эхом на дисплей; ungetch (sim), возвращающая
символ sim назад в буфер ввода; kbhit(void), возвраща-
ющая ненулевое значение после нажатия клавиши.
Из перечисленных выше функций языка СИ для ото-
бражения псевдографической информации в ПАСКАЛе
не определены аналоги подпрограмм gettext, gettextinfo,
movetext и puttext. Не существует в ПАСКАЛе также
подпрограммы, подобной textattr. Однако вместо этого
объявлена переменная TextAttr, которой присваивается
значение атрибута выводимых символов. При работе с
текстовыми окнами в языке ПАСКАЛЬ используются
обычные процедуры ввода и вывода информации — READ,
READLN, WRITE, WRITELN. Функции cgets, cprintf,
cputs, cscanf, putch, getch, getche, ungetch и kbhit специ-
фичны только для языка СИ.
Остальные подпрограммы можно использовать без из-
менений. Они полностью аналогичны одноименным функ-
циям языка СИ. Все эти подпрограммы описаны и реали-
зованы в разделе библиотеки CRT, который при их исполь-
зовании необходимо подключить к программе.
В разделе CRT описана также функция KEYPRESSED
логического типа, которая принимает значение TRUE,
если на клавиатуре была нажата любая клавиша. Полез-
ной может оказаться также функция READKEY, пред-
назначенная для считывания символа с клавиатуры.
Рассмотрим программу на языке СИ, использующую различные
функции для работы с окнами и псевдографической информацией:
Haclude <stdio.h> /* пример 9 */
Haclude <coaio.h>
Haclude (alloc.h>
lain ()
[ unsigaed char strflOO};
iat x,y; void sha, taallocO;
textattr(7); /* установка атрибута »/
clrscrl); /* стирание экрана »/
wiadowf5,5,25,10); /I задание окна </
400
cputst"Работа с окиси Г); gotoxy(l,2);
highvideof); /х повииает яркость иосдедущего текста »/
eputsCnOBfflima ЯРКОСТЬ"};
Ьшиа11ос(252); /х янделение памяти х/
gettext(5,5,25,10,ha); /х сохранение фрагмента тектса х/
gotoxyl10,1);/х переходит ио дайнам координатам
относительно окиа х/
InslheO; /» перемежает строку с курсором (текст
"Работа с окном Г) иа позиции вниз X/
gotoxy(7,2); delay!1000);
clreoll); /х стирает символы а окне ot позиции
курсора до конца строки (останется слово 'Работа') х/
gotoxy(l,3); delay(2000);
delliael);/х стирает все строку Ч0ВИЕ880Я ЯРКОСТЬ' »/
delay!1000); gotoxyl1,3);
сриСзСВведите строку'); gotoxy(l,();
aoravideod; /X устанавливает нормальную яркость »/
textattr(1); cscanf("Is",str); clrscrl);
gotoxy(l,2); cprintf("Is", str);
gotoxyd.l); cputsfnepeHoc текста'); delay( 10 00 );
textattr(0x70); /» сейчас инверсное изобрахеиие х/
novetext!5,5,20,6,(5,2); /х перенос текста х/
delay(lOOO);
nindos!35,10,55,15); /х задание окиа х/ clrscrl);
cputsl'Работа с окном 2"); gotoxy(3,2); delay(1000);
cprintf!“Xd t « -- Xd",37,18,37(18); gotoxyll,3);
cputs("Введите строку'); gotoxyd.l);
cscanf("ts",str); gotoxyll,5); cpriatfl'ls ",str);
putch(181); /х вывод псевдографического символа с
номером 181 в окио экрана х/
delay!1000);
х = wherexl); /х значение координаты X »/
у : shereyl); /» зиачеиие координаты Y х/
clrscrl); gotoxyd,3);
cprintfl'X - Xd; Y = Xd'.x.y); delay(1000);
puttext(10,11,60,19,Ье);
nindowl10,5,И,12); clrscrl):
/х яаяод псевдографического изобрахеиие в заданное окио х/
/х первая (верхняя линия прямоугольника) и последуицке
Функции показняаат дяа способа вывода изобоакеиня х/
cprintfl’ ЫсЫсЫс", 218, 136,136,136 , 136, 131);
gotoxy(2,2);
cpriatfC '); gotMy(2,3);
cprintf(" '); gotoxy(2,4);
cprintf(' '); gotoxy(2,6);
ергintf(" '); gl)toxy(2,6);
cprintf(' — '); delay(dQOO);
В программе с задержкой через I с демонстрируется выполнение
различных функций, назначение которых было рассмотрено выше и
дополнительно указано в содержательных комментариях. В конце
программы в окне экрана появится псевдографическое изображение
При этом использованы следующие псевдографические элементы и
символы таблицы ASCII:
г - 210, - - 136, , - 191, | -- 173, пробел •• 32,
ё - 176, L - 132, 1 - 217.
14 Скляров В. А.
401
В заключение укажем возможные десятичные и в скоб-
ках шестнадцатеричные коды всех псевдографических
элементов:
| -- 176 (ВО); | - 177 (В1); | - 178 (В2); | - 178
| - 180 (В4); j - 181 (В5); j - 182 (В6); , - 183 (В7)
; - 184 (В8); j - 185 (ВО); | - 186 (ВА); , - 187 (ВВ;
! - 188 (ВС); » -• 189 (BD); J - 190 (BS); , - 191 (BF)
L - 192 (СО); г - 193 (Cl); r - 184 (С2); - 185 (СЗ)
- - 186 (С4); j- - 197 (С5); |= - 188 (С6); j- - 188 (С7)
t - 200 (СЗ); f - 201 (СО); - - 202 (СА); f -- 203 (СВ)
|= - 204 (СС); = - 205 (СВ); «= - 206 (СЕ); t - 207 (СЕ).
1- - 208 (DO); f -- 208 (D1); т - 210 (D2); I - 211 (D3):
t - 212 (D4); r - 213 (D5); г - 214 (D6); | - 215 (D7);
f - 216 (D8); J - 217 (DO); r - 218 (DA); g - 219 (DB);
B- 220 (DC); | - 221 (DD); |- 222 (DS); s - 223 (DE).
Приведенная ниже программа на языке СИ демон-
стрирует возможности создания собственных наборов зна-
ков для расширенной таблицы ASCII. Например, она не-
обходима при выводе русских букв с помощью функций
outtext и outtextxy:
Include (stdio.b /» пример 10 »/
iinclude (graphics.Ь> /» графический реши »/
•include <dos.h>
iaiu() /» создание собстяеииаи иабороя эиакоя дхи
расаиреииой табдяца ASCII »/
( int gd-9ETECT,gtt,k;
/» xg(() •- кассии, и котором хранятся графические образа
сяияояоя дди расииреииой табдица ASCII (десятичные
иоиера от 128 (перяве 8 байт) до 255 Д/
char str(80J,
xg() - (Oxfc,0x44,0x30,0x30,0x44,Oxfc,0x0,0x0,
0x80,0x40,0x20,0x48,0x80,0x20,0x0,0x0,
0x20,0x20,0xf8,0x20,0x20,0x0,0x18,0x0);
/» Фуихцяя poke занисаааед значение из третьего параметра
и сегмент, заданный нерини параметром, со скедениек,
заданным яторам параметром; JS - псевдопеременная,
соотяетстяуоаая регистру DS микропроцессора »/
роке(0,126, _DS);
poke(о,124,xg); /» xg - адрес начала иассияа zg() »/
ри15('Введите русские букяо й, В, В");
/» авод строки с бяааии й, В, В. Вместо них будут ви-
402
водиться знай cjmmu, бньае иди равно, мве-ивдс »/
gets(str);
риЬа(*Вас«та6ный коэффицяент?*); scanffW ,4к|;
initgraph(&gd,4ga,");
setcolor(4); /» ктановва красного цвета »/
setteitsiy 1е(0,0,к|; /» тешете сннцовоц в к раз »/
/» яиво* матенатической форнуди ди примера »/
outtestv(10,10,'a(4»B№(IM)');
setcolor(5); /» рстанови фводетояого цвета »/
outteitsjl10,11!,str);/» вивод введенной строки str »/
closegraphO; )
Массив zg содержит 24 байта с информацией о трех
новых символах: S, + . Для каждого одного символа
требуется 8 байт. Кодирование их осуществляется в соот-
ветствии с правилами, проиллюстрированными на рис.
11.1. Первый из 8 байт — верхняя полоска символа, по-
----------------------у
----------------------5
Рис. 11.2. Образцы наполнителей
103
следний — нижняя. Первые 8 байт массива zg соответ-
ствуют коду 128 расширенной таблицы ASCII, вторые —
коду 129 и т. п. В приведенной программе код 128 выра-
батывается при нажатии клавиши А (русская буква),
129 — Б и т. д. Таким образом, при нажатии клавиши А
в графическом режиме на экран будет выведен знак S,
вместо Б — знак X. вместо В — знак ±. Адрес первого
байта в массиве zg необходимо поместить на место вектора
31 в начальную область оперативной памяти, причем в
байты 31X4= 124 и 125 нужно записать смещение, а в
байты 126 и 127 — адрес сегмента (байт с большим
номером является старшим). Делается это с помощью
библиотечной функции СИ роке. Ее первые два параметра
задают сегмент и смещение для записи информации, а
третий параметр — это записываемые данные. Адрес
сегмента массива zg содержит псевдопеременная___DS, а
смещение — само имя массива. Все последующие поясне-
ния приведены в комментариях к программе.
На рис. 11.2, а представлены образцы заполнителей,
стандартно заданных в графических системах для различ-
ных фигур. Рядом с наполнителем указан его номер. На
рис. 11.2,6 показаны номера и образцы стандартных
линий.
В заключение перечислим номера возможных цветов
основной палитры: 0 — черный; 1 —синий; 2 — зеленый;
3 — голубой; 4 — красный; 5 — фиолетовый; 6 — корич-
невый; 7 — светло-серый; 8 — темно-серый; 9 — светло-
синий; 10 — светло-зеленый; 11 —светло-голубой; 12 —
светло-красный; 13 — светло-фиолетовый; 14 — желтый;
15 — белый.
12. ПРЕРЫВАНИЯ MS-DOS
12.1. ОБЩИЕ СВЕДЕНИЯ
Механизм прерываний обеспечивает приостановку те-
кущей работы ПЭВМ для обработки ситуации, требующей
немедленного вмешательства. Прерывания можно разде-
лить на три группы: аппаратные, логические и програм-
мные. Аппаратные прерывания возникают в результате
нажатия клавиши на клавиатуре, прихода очередного
импульса от датчика времени, появления сигналов от
дисководов и т. п. Логические, или процессорные, пре-
рывания имеют место при нестандартных ситуациях в ра-
боте микропроцессора (деление на нуль, переполнение
регистров, появление точки останова и т. п.). Последняя
и самая многочисленная группа — программные преры-
вания — вырабатываются тогда, когда одна программа
хочет получить определенный сервис от другой.
Каждое прерывание имеет уникальный номер, с кото-
рым связана определенная программа для обработки
возникшей ситуации. На рис. 12.1 показан общий меха-
низм обращения к такой программе. В первых 1024 байтах
начальной области оперативной памяти размещаются век-
торы прерываний. Каждый вектор занимает 4 байта.
Два старших из них содержат сегментный адрес блока
памяти, в котором содержится программа обработки
прерывания. В двух младших байтах записано смещение
для этой программы. Если вызывается прерывание с номе-
ром 9, вектор прерывания занимает 36, 37, 38 и 39-й байты
оперативной памяти, причем в 38-м и 39-м байтах записан
сегментный адрес, а в 36-м и 37-м —смещение. При вы-
зове прерывания содержимое текущих регистров выпол-
няемой программы загружается в стек; сегментный адрес
и смещение программы обработки прерывания передаются
в регистры CS и IP. В результате приостанавливается
текущий процесс и выполняется программа обработки
прерывания. После ее завершения из стека восстанавли-
405
АДРЕС /'^НАЧАЛЬНАЯ
00000 ОБЛАСТЬ
ОПЕРАТИВНОЙ
ПАМЯТИ
Рис. 12.1. Обращение к программе обработки прерывания
вается содержимое регистров основной программы и про-
должается прерванный процесс.
Во многих практических приложениях программе обра-
ботки прерывания необходимо передать некоторые данные.
Для этих целей используются регистры микропроцессора.
Перед вызовом прерывания в них необходимо поместить
передаваемые данные, а после завершения его обработки
получить результаты. Напомним о записи вида ESrBP,
которая означает, что рассматривается слово длиной
32 бита, причем его первая часть (16 бит) находится
в регистре ES, а вторая — в регистре ВР.
Обслуживание прерываний нижнего уровня осущест-
вляет базовая система ввода-вывода (BIOS). Соответ-
ствующие программы используются для непосредственно-
го управления аппаратными компонентами. Другие пре-
рывания относятся к более высокому уровню, и их’обслу-
живание осуществляется модулем IBMDOS.COM опера-
ционной системы (ОС). Одно из прерываний с номером
33 позволяет обратиться к множеству функций ОС, кото-
рые подробно будут рассмотрены далее. Кроме того, зна-
чительная часть векторов верхнего уровня зарезервиро-
вана для будущего развития ОС. Их можно использовать
и для разработки собственных программных средств обра-
ботки прерываний. При работе с прерываниями часто
используются так называемые программы-фильтры. Они
устанавливаются на входе или выходе стандартной
процедуры BIOS или ОС и обеспечивают выполнение
406
дополнительных действии, заданных пользователем, на-
пример переключают таблицу для знакогенераторов после
нажатия одной либо нескольких активных клавиш (hot
key).
В гл. 8 уже говорилось о том, что существуют три
основных способа построения резидентных программ та-
кого типа. Первый способ предполагает вызов программы-
фильтра через некоторый вектор, затем передачу управ-
ления стандартной процедуре обработки прерывания и,
наконец, выполнение некоторых дополнительных действий.
При втором способе сначала выполняются дополни-
тельные действия, а затем управление передается стан-
дартной процедуре. Передача управления при этих двух
способах осуществляется командами ассемблера типа call
и jmp. Далее будет показано, как это делается в языках
высокого уровня (на примере СИ). Третий способ описы-
вается ниже.
Предположим, что у нас есть некоторое прерывание
с номером N (рис. 12.2). Тогда его вектор расположен
ПРОГРАММА
ОБРАБОТКИ
ПРЕРЫВАНИЯ
ОПЕРАТИВНАЯ
ПАМЯТЬ
Рис. 12.2. Иллюстрация третьего способа построения программ-
фильтров
407
по адресам: 4N, 4N4-1, 4N-|-2 и 4N4-3. Перенесем его
на место вектора М (М<256). Для М можно отвести лю-
бой свободный фрагмент в верхней области первого кило-
байта оперативной памяти. Тогда содержимое байта по
адресу 4N надо переписать на место 4М, содержимое
байта по адресу 4N+1 — на место 4М-Т 1 и т. п. После это-
го в байты вектора N необходимо записать сегментный
адрес и смещение программы пользователя. Теперь обра-
щение к вектору N вызовет запуск на выполнение прог-
раммы пользователя. В ходе ее выполнения можно вызвать
прерывание N, обратившись к вектору М.
Подобные действия необходимы во многих практи-
ческих случаях. Например, пользовательскую программу-
фильтр можно сделать резидентной и активизировать
некоторый ее фрагмент при нажатии определенной клави-
ши или группы клавиш. В результате на фоне других
программ можно менять шрифты, просматривать таблицу
ASCII-кодов, производить арифметические вычисления,
отбрасывать отдельные символы, запрещая их отображе-
ние на экране, и т. п.
12.2. СРЕДСТВА ДЛЯ РАБОТЫ С ПРЕРЫВАНИЯМИ
Работа с прерываниями будет иллюстрироваться при-
мерами программ, написанных на языках СИ и ассембле-
ра. В связи с этим охарактеризуем главные средства
языка СИ, используемые для подобных целей. Они в ос-
новном описаны и объявлены во включаемом файле
dos.h. В нем используются определенные записи, имею-
щие следующий вид:
struct fcb ( /» соответствует блогу уиравлеиии (айлом »/
char fcb_drive; /» ив двсяовода: II - (; 1 - В в т.в. »/
char fcbja»e[8]( /» » (ata »/
fcb_eit(3J; /» расивревяе (aha »/
short fcbjurblk, /» номер тенцего бига >/
fcbjecsise; /» размер lomecioi завися »/
loBg fcbjilsize; /« размер (aha »/
short fcbjate; /« дата модв(вяацвв (ata «/
char fcb_rezv(10], /» зарезервнроваввав область ОС »/
fcb.currec; /» номер тегудей завися »/
loBg fcb_rando«; ) /» вомер завися врямого достува »/
struct xfeb ( /У дополнен байтамв расивренвого ?СВ »/
char xfcbjElag; /» ff - (лаг раснреввого FCB »/
char rfcbjesv(5]; /» зарезерввроваввая область ОС »/
char rfcbjttr; /« атрибут эярава У/
struct fcb ifcbjcb; )
struct dfree ( /» вв(ормацвя о двсяе л/
UBsigBed df jvail; /» доступво мастеров »/
408
unsigned df.total; /» обцее ввело кластеров в/
unsigned df_bsee; /в байт в секторе »/
unsigned df_sclus; /• секторов в квастере к/ )
struct fatinfo ( /> вйорвацн о табдкце размеценя файлов >/
char fi.sclus; /к секторов в кластере »/
char fi.fatid, /в ТРФ байт »/
int fijclus; /» ввело кластеров в/
int fi_bysec; /в байт в секторе »/ )
struct devhdr 1 /в запись для заголовка драйвера (евстеввал
область Device Header Layout) в/
long dhjeit; /» адрес еястеииой обдаств еледрвдего драйвера »/
short dh.attr; /» атрибут устройства »/
unsigned short dhjtrat; /» еведевве дав стратегия в/
unsigned short dh.inter; /в еведенве для обработчика »/
char dh_nane(8J; /» вив устройства в/ )
struct ti»e ( /♦ информация о вревевв в/
unsigned char tijin; /• минуты в/
unsigned char tijiour; /» чаев */
unsigned char ti.hund; /» сотне Доле секунды в/
unsigned char ti.sec; /» секунды в/ )
struct date ( /в ввфорвацвв о дате в/
int dajear; /в год, начиная е 1980 в/
. char da.day; /в день меевца в/
char dajon; /в месяц (1 - январь; 2 - февраль г т.п.) в/ )
struct S08DHEGS (
unsigned Int ах, bx, сх, dx, si, di, eflag, flags; );
struct BYTEREGS (
unsigned char al, ah, hl, bh, cl, ch, dl, dh; ];
union REGS (
struct EORDREGS x;
struct BYTEREGS h; );
struct SREGS (
unsigned int es, cs, ss, ds; );
struct REGPACK (
unsigned r.ax, r_bx, r_cx, r.dx, r_bp, rji, r_di,
rjs, r_es, r.flags; );
Элементы es, cs, ss, ds, ax, bx, ex, dx, bp, si, di, al, ah, bl,
bh, cl, ch, dl, dh связаны с регистрами микропроцессора.
Элементы flags, eflag отражают состояние регистра
признаков микропроцессора. В частности, eflag — это
признак переноса.
Опишем функции, определенные в файле dos.h:
absread (номер дисковода, число секторов для чте-
ния, номер начального логического сектора, void *bf) —
считывает данные из секторов диска в буфер, на который
указывает bf. Номер дисковода равен О—для А, 1 —
для В и т. п. Первый логический сектор имеет номер О.
Функция возвращает значение О при успешном заверше-
нии и — 1 при ошибке;
abswrite (номер дисковода, число секторов для записи,
номер начального логического сектора, void *bf) — по-
409
добна предыдущей функции, но используется для записи
информации;
allocmem(unsigned размер, unsigned *seg) —выде-
ляет память в заданном сегменте (*seg) со смещением О
(размер памяти задается в параграфах); возвращает — 1
при успешном завершении, в противном случае дает раз-
мер наибольшего доступного блока;
bdos(номер функции ОС, unsigned dx, unsigned al) —
вызывает и выполняет функцию MS-DOS, доступную через
прерывание 33; возвращает значение регистра АХ (здесь
dx и al — значение регистров DX и AL при вызове bdos);
bdosptr(номер функции ОС, void *arg, unsigned al) —
подобна предыдущей функции, но позволяет использовать
указатель на аргумент (arg), который сохраняется в ре-
гистре DX либо DS:DX; возвращает значение регистра
АХ либо — 1 при ошибке;
ctrlbrc(int(*prog) (void)) —прерывает работу прог-
раммы и осуществляет выход в среду ОС, если функция
prog возвращает значение 0; если она возвращает другое
значение, прекращения работы программы не происходит;
disable (void) — запрещает все прерывания, кроме не-
маскируемых;
enable (void) — разрешает прерывания;
freemem(unsigned seg) — освобождает память в сег-
менте seg, предварительно выделенную функцией alloc-
mem; возвращает 0 при успешном завершении и — 1 при
ошибке;
geninterrupt (номер прерывания) — вызывает и выпол-
няет прерывание с заданным номером;
getcbrk(void) — возвращает 0 при отсутствии провер-
ки на Ctrl — break (УПР — СТОП) и 1 при ее наличии;
getdate(struct date *d) —позволяет получить дату,
установленную в ОС (см. запись типа date); ,,
getdfree(unsigned char номер дисковода, struct dfree
*dt) — позволяет получить размер свободного простран-
ства на диске;
getfat(unsigned char номер дисковода, struct fatinfo
*dtf) — позволяет получить информацию из таблицы раз-
мещения файлов для дисковода с заданным номером;
getfatd(struct fatinfo *dtf) — позволяет получить ин-
формацию из текущей таблицы размещения файлов;
getpsp(void) — возвращает сегментный адрес PSP —
префикса программного сегмента (program segment
prefix);
410
gettime(struct time *t) — позволяет получить время,
установленное в ОС;
void interrupt(*getvect(HOMep прерывания)) () — по-
зволяет прочитать значение вектора прерывания с задан-
ным номером и интерпретировать это значение как ука-
затель типа far на функцию обработки прерывания;
getverify(void) —возвращает единицу, если осущест-
вляется верификация записи информации на диск,
и нуль — в противном случае;
inport (номер порта) — вводит целое значение (int) из
порта с заданным номером;
inportb (номер порта) —вводит байт данных из порта
с заданным номером (вместо inportb можно использовать
inp);
int86(номер прерывания, union REGS *inregs, union
REGS *outregs) — вызывает и выполняет прерывание
с заданным номером. Значения *inregs копируются в ре-
гистры микропроцессора до осуществления прерывания.
После завершения прерывания значения регистров копи-
руются в *outregs и устанавливается состояние признака
переноса x.cf lag (если он не равен нулю, значит, произошла
ошибка);
int86x(HOMep прерывания, union REGS *inregs, struct
SREGS *segregs) — в дополнение к int86 до осуществле-
ния прерывания копируются значения segregs (ds и es).
Это требуется при использовании больших моделей памя-
ти. После завершения прерывания восстанавливается
DS;
intdos(union REGS «inregs, union REGS *outregs) —
вызывает и выполняет прерывание 33 MS-DOS;
intdosx(union REGS *inregs, anion REGS *outregs,
struct SREGS *segregs) — имеет те же отличия от
intdos', что и int86x от int86;
intr (номер прерывания, struct REGPACK *preg) —
выполняет прерывание с заданным номером; входные
и выходные данные сохраняются в полях записи *preg
типа REGPACK;
кеер(статус, размер) — возвращает в MS-DOS содер-
жимое поля статуса, завершает программу и оставляет ее
резидентом; размер оставляемой резидентной программы
необходимо задавать в параграфах;
outport(номер порта, целое значение) —выводит ука-
занное целое значение в порт с заданным номером;
outportb(номер порта, байт) —выводит байт данных
в порт с заданным номером (вместо outportb можно ис-
пользовать outp);
• 411
реек(сегмент, смещение) — по заданным сегментному
адресу и смещению возвращает целое значение (int);
peekb(сегмент, смещение) — по заданному сегментно-
му адресу и смещению возвращает байт данных (char);
роке (сегмент, смещение, целое значение) — записы-
вает заданное целое значение в указанное место;
pokeb (сегмент, смещение, байт) —записывает задан-
ный байт(тип char) в указанное место;
randbrd(struct fcb *f, число записей) — вводит задан-
ное число записей, используя блок управления файлом *f;
возвращает нуль, если все записи прочитаны; единицу —
при достижении конца файла и условии, что последняя
запись полностью прочитана; два — в случае необхо-
димости повторного чтения; три — при достижении конца
файла и неполном считывании последней записи;
randbwr(struct fcb *f, число записей) —подобна
randbrd, за исключением того, что осуществляется не
чтение, а запись; возвращает значение нуль, если все за-
писи перенесены; единицу — при отсутствии достаточно-
го места на диске; два — при необходимости повтор-
ной записи;
setblock(unsigned seg, новый размер) — изменяет раз-
мер ранее выделенной с помощью функции allocmem па-
мяти;
setcbrk(проверка) —включает (если проверка равна
1) и выключает (если проверка равна 0) проверку на
Ctrl -Break (УПР -- СТОП) ;
setdate(struct date — устанавливает дату для
MS-DOS;
setvect(HOMep вектора, void interrupt(*isr) ()) — уста-
навливает новый вектор прерывания. Здесь isr —указа-
тель на функцию, которая будет вызываться по прерыва-
нию с заданным номером (поле «номер вектора»). Если
isr — функция СИ, она должна быть объявлена с модифи-
катором interrupt. Функция setvect устанавливает вектор
прерывания с заданным номером, вызывающий функцию
(*isr);
setverify(признак) —если признак равен 1, каждая
дисковая операция записи будет сопровождаться опе-
рацией чтения для проверки корректности результата;
если признак равен нулю, проверка не выполняется;
unlink (const char ^filename) —удаляет файл с задан-
ным именем; если файл с именем *filename имеет атрибут
«только чтение», удаление производиться не будет;
char far *getdta(void) — возвращает указатель на
412
текущую область памяти для передачи данных — Disk
Transfer Area (DTA);
FP__OFF (указатель на объект) — возвращает смеще-
ние объекта типа far (дальний указатель);
FP__SEG(указатель на объект) — возвращает сег-
ментный адрес объекта типа far;
void far *МК___FP (сегментный адрес, смещение) —
возвращает указатель типа far на объект по его сегмент-
ному адресу и смещению.
12.3. ПРЕРЫВАНИЯ БАЗОВОЙ СИСТЕМЫ
В ВОДА-ВЫ ВОДА
12.3. 1. Общие сведения
На базовую систему ввода-вывода (BIOS) и ОС возла-
гается задача обслуживания прерываний нижнего уровня.
Перечислим выполняемые ими функции с указанием
десятичного и в скобках шестнадцатеричного номеров:
обслуживание ситуации, возникающей при делении на
нуль — 0 (0);
перевод микропроцессора в пошаговый режим (при
этом должен быть установлен в единицу флаг TF [1] ре-
гистра признаков) — 1 (1);
немаскируемое прерывание, возникающее при обра-
ботке ситуаций, требующих немедленного вмешательства
(например, падение напряжения питания) —2 (2);
появление точки останова в последовательности ко-
манд — 3 (3);
обслуживание ситуации, возникающей при переполне-
нии регистров арифметического устройства — 4 (4);
печать копии экрана — 5 (5);
обработка сигнала от датчика времени (таймера) —
8 (8);
обработка сигнала от нажатия клавиши на клавиатур
ре — 9 (9);
обработка сигнала окончания обмена от- накопителя
на магнитных дисках— 14 (Е);
функции управления дисплеем — 16 (10);
запрос списка подсоединенного оборудования —
17 (И);
запрос размера оперативной памяти—18 (12);
функции для управления накопителями на магнитных
дисках — 19 (13);
функции для управления коммуникационными кана-
лами — 20 (14);
413
функции для управления дополнительно подключаемы-
ми устройствами и расширенной памятью—21 (15);
функции для управления клавиатурой—22 (16);
функции для управления принтером — 23 (17);
обращение к встроенному БЕЙСИКУ — 24 (18);
перезапуск системы — 25 (19);
функции для запроса и установки текущего времени
и даты — 26 (1А);
прерывание от клавиатуры (при нажатии клавиш
Ctrl — Break) —27 (IB);
прерывание по таймеру со стороны пользователя —
28 (1С);
сегментный адрес и смещение для таблицы параметров
инициализации дисплея (Video Parameter Table) — 29
(Ю);
сегментный адрес и смещение для таблицы параметров
накопителя на гибких магнитных дисках (Diskette
Parameter Table) — 30 (IE);
сегментный адрес и смещение таблицы символов
с кодами 128—255 для графического режима работы
дисплея — 31 (1F).
12.3. 2. Аппаратные прерывания
Приведем примеры программ для работы с аппаратными прерыва-
ниями. Первая из них работает с вектором 8 и позволяет создать рези-
дентный модуль для отсчета текущего времени. В ПЭВМ каждые
55 мс (примерно 18,2 раза в секунду) встроенный датчик времени обра-
щается к прерыванию с номером 8. Учитывая это обстоятельство, можно
перехватывать аппаратное обращение и выполнять те действия, которые
необходимы пользователю. В нашем примере это позволяет организо-
вать отсчет времени. На экране (в правом верхнем углу) будет появ-
ляться строка, содержащая двухразрядные десятичные значения часов,
минут и секунд. Модуль является резидентным и работает на фоне любой
другой программы. Его текст написан на языке СИ и приведен ниже:
о.
^include <dos.h> /в ирограииа ди вивода на эхраи в/
llnclude <stdllb.h> /» текучего времени (СПОСОБ 1)»/
void interrupt (Bold)(); /в old - ухазатевь на фуакцкв в/
void interrupt pre8() /в заидсх этой фувкцЕИ будет осддест-
вхеи вместо 8-го нрерываввв >/
( int в,Ь; /В — miijtu; h -- часа В/
unsigned char str(20],rax,rex,rdx;
static char ct; /в ct — ди нодсчета чисха «ре-
ртам* в еекувду »/
void ppstr(int at,int x.int y, unsigned char s(J);
(Bold)(); /> вызов орнгинахьиой фувкцвв BIOS >/
iffctti 18) ( ct - 0; rax=JX; rcx=_CX; rdx=JX;
/» смена информации о времени одна раз в секунду (снача-
да сокранавтея установи исподьзуемых регистров ЙП) »/
JX - 0x0200; /» полученве формация о времени »/
414
genlnterrupt(26); /» ввзоа прернваммн 26 в/
а - _CL; /» > -- текущее змачеие «вин */
h = _СН; /» h - текущее змачеие часов »/
/»«* СЕКУНДЫ г»/
itoa( JH.str, 16);
/» преобразовавве целого чвсла в строк? str в
представкеняе его в вестяадцатерячяой форме »/
p?str(112,Т1,1');/» вывод ивформацив мз строка »/
ppstrl112,TI .1, str); /» str ва эвраи двспдея */
/Ш МИНУТЫ »»»/
itoa(«,str, 16);
ppstr(112,75,0,' :'); ppstr(112,75,0,str);
/»»» ЧАСН »»»/
itoa(h,str,16);
ppstr (112,72,0, “ :"); ppstr( 112,72,0,str);
JI=rni; _CX-rcx; Jbrdi; /» воссгавоввевве
регистров »/ ] ] /» ковец фуикцив »/
aainf)
( struct HKGPACK rp; /» запвсь ддя прериваввв »/
void Interrupt prel(); /» функция prel доима вветь
Tin interrupt »/
unsigned aeajize : (JS - _CS) t (JJP/161) t 33;
/* Tat моно ВВЧВС1ВН объем памвтв программ, готорав
остается резидентной (тонко дп модели Saall); дп
модели Tiny (преобразование в СОН файлу) здесь дон-
ка бить строка: unsigned leijke = (_SP/16l) » 1; »/
old - getvect(0s3); /» в переменной old сохрапетсн
точка ввода в орвгввшвдв программу BIOS в/
setvect(3,pre3); /* вместо обработки сигнала от дат-
чика времени будет вызываться папа программа рге8 »/
rp.rjxJxSIll; гр.r_dx=nen_siKe; intr(33,Arp);
/» прерываипе 33, функция 0x31 - закончить в ос-
таться резидентом »/
]
void ppstr(int attr,int x,int y.unsigned char atr[})
/» функция вывода строки тевета ва экран дисплея »/
[ int k,i=-l,r; /» г - номер рехима дп дисплея в/
int seg; /» сегментный адрес экранной иамяти »/
/» определение тевцего видеорехима в в зависимости от
него сегментного адреса эвранной мамнч в/
JH-0xf; geninterrupt( 16); г: Jb;
if(r<7) seg-ОхШОО; else
if(r=-7) seg=0xB000; else seg-OxAOOO;
/> вмбор места в эвраимой памяти дн мачаха строки в/
к : 160Ву ( 2»Х;
»hile(str(Hi] -\0’1
( pokeb(seg,к,str(i]); kt=2;
if(attr С) pokeh(seg,к-1,attr); ]
/в запись в экраинуи область памяти ннформации о сим-
волам текста н атрибутам в/ ]
С помощью функции setvect в качестве вектора 8 задается началь-
ный адрес программы рге8. В подобных случаях программы должны быть
объявлены с ключевым словом interrupt. В примере добавлено слово
void, что указывает на отсутствие возвращаемого функцией значения.
Наряду с восьмым вектором в программе использованы прерывания
16, 26 и 33. Первое и последнее из них будут описаны ниже, поэтому
остановимся только на векторе 26 (lAis) • Прерывание 26 позволяет
415
обратиться , к одной из восьми функций. Номер требуемой функции
устанавливается в регистре АН перед вызовом. В примере задан номер 2,
что позволяет прочитать текущее время из энергонезависимой памяти
(CMOS-memory). Часы, минуты и секунды будут записаны в регистрах
CH, CL и DH. Формат данных — шестнадцатеричный. Например, если
в СХ записано число 0x1258, то это означает 12 часов 58 минут. Функция
itoa преобразует число (первый аргумент) в строку (второй аргумент)
с заданной системой счисления (третий аргумент). Шестнадцатеричный
формат указания времени определил необходимость выбора системы
счисления с основанием 16. Если при обращении к прерыванию 26 возвра-
щается значение 1 во флаге CF(nepenoca) регистра признаков, датчик
времени не работает.
Кратко охарактеризуем другие функции:
чтение числа подсчитанных импульсов (АН=0). На выходе: СХ:
DX — число импульсов с момента сброса, которые следуют через
55 мс (старшая часть в СХ);
установка начального значения числа импульсов (АН= 1). На входе:
СХ: ОХ — заданное число (старшая часть в СХ);
установка времени для энергонезависимой (CMOS-memory) памяти
(АН = 3). На входе: CH, CL — часы и минуты, DH — секунды (формат
задания тот же, что и у функции 2). Если задать DL= 1, время указы-
вается с периодом 12 часов;
чтение даты из энергонезависимой памяти (АН=4). На выходе:
СХ — год (например, 0x1989 — это год 1989), DH — месяц, DL — число
(например, DX= 0x0921— 21 сентября). Если CF= 1, датчик даты не
работает;
установка даты в энегонезависимой памяти (АН=5). На входе:
СХ — год, DH — месяц, DL — число;
установка времени выдачи предупреждающего сигнала (АН =6).
На входе: CH, CL — часы, минуты, DH - секунды. На выходе: если
CF— 1 (признак переноса), предупреждающий сигнал активен (см.
также § 1.4, 1.5);
сброс предупреждающего сигнала (АН=7).
Еще одной особенностью приведенной программы является то,
что в ней не использованы функции вывода типа printf, и для этих целей
написана собственная функция ppstr, которая записывает ASCII-код
символа и его атрибуты в соответствующие байты экранной памяти.
На входе она получает код атрибута (attr), горизонтальную (х) и верти-
кальную (у) позиции первого символа в строке str, которая принимается
в виде четвертого параметра. Сегментный адрес (seg) экранной памяти
вычисляется с помощью функции Oxf прерывания 16. Переменная к ука-
зывает адрес байтов с ASCII-кодами и атрибутов (атрибут 112 задает
вывод инверсного изображения). Обратим внимание на то, что рези-
дентные программы нельзя выполнять в среде ТУРБО СИ (необходимо
предварительно выйти в среду ОС).
Второй пример показывает правила получения резидентного мо-
дуля типа СОМ. Программа реагирует на специальные клавиши. Если
нажать клавиши УПР — ф (Ctrl — Shift) слева или УПР —справа,
на экран будут выводиться разные тексты. Эти простые действия
можно заменить любыми сложными при сохранении общей идеологии
построения модуля. Он остается резидентным в памяти и, следовательно,
может работать на фоне любой другой программы. Ниже приводится
пример:
416
/ttttttttttitmtmtmtimtttttmimttttttmttt/
/* Резнде«т«ая програииа, срабатывавшая при вадатнв »/
/* хлавак Ctrl - Shift »/
/HMtnutittmttmttniinmmudttttttWm/
linclude <stdio.h> /» предупреядевне хоипововшнка »/
linclude <dos.h> /» no stack следует игиорнровать »/
/< Ниппе HI файл с иодельл паиятн Tiny, затея »/
I* преобразуйте его с поколь» EXE2BIN в СОМ файл »/
typedef void interrupt int.fnl);
intjn told; /» old - указатель la фуякцяв, которая
noser визиваться через прерывания */
extern unsigned _heaplen = 300: /» Jieaplen - длила дца-
иическн распределяеиой области
паши. Опредедева в файде dos.h »/
extern unsigned _stklen - 300; /» jtklen определяет
разиер стека »/
typedef struct biosJIT /» здесь использована одно- */
( unsigned Eshift:!, /» битовые поля, в когорт */
unsigned Lshift:1; /* расписали состояния кда- */
unsigned Ctrl:!; /« вил нз области BIOS (си. »/
unsigned Alt:!; /* табл. 1.3). Адрес соот- »/
unsigned Scroll_Lock:l; /» ветствувдего байта »/
unsigned Nun_Lock: 1; /» 0--041Т Си. дополввтелъ- Ч
unsigned Caps_Lock:l;/» ио параграф 2.1 »/
unsigned Ins:l;
) key; /» key - переиелная этого типа »/
typedef unsigned char disp[25][80}[2]: '» disp - это трех-
иерннй насснв дда экранной' памяти: 25 - число строк;
80 - число етолбцив; 2 - символ и атрибут »/
disp far tvideo; /♦ video - это дальний (far) указатель иа
начало нассивэ disp «/
key huge «sh; /! sh - это дальний вормалнзованиый (huge)
указатель на битовую запись key »/
/* Функция вывода строки str иа экран дисплея, иачниая »/
/« с позиции (х.у) с атрибутов attr «/
print_it(int x,int у,int attr,char tstr)
[ int i;
for(i=0;irstrlen(str);it>) /» здесь работа с экран-
ной нанять» адет через указатель video »/
( (tvideo)[y][xti][0] - str[ij; /« в четний байт за-
пнсыяается символ »/
(tvideo)[у][xti][1 ] - attr; /« в нечетный байт за
писывается атрибут »/
1
1
/tttttttttttttttttttttt*ttttttttttttttttttttttttttt/
/» Новая функция, вызываемая через S-е прерывавие »/
«»»»»»»«»»»*»»»»»»»»»»»»»/
void interrupt new()
[ (»old)(); /» вызов оригинальной фувкцнн BIOS «/
if(sh->Ctrl 44 sh->Hshift) /• если наши Ctrl и
Shift справа «/
printJt(55,12,2,"IM8ET ИЗ МРТИ СПРАВА'|;
else if(sh->Ctrl 44 sh->Lshift) /* если иахати
Ctrl и Shift слева t/
417
print_it( 15,12,1."ПРШТ НЗ нт США"):
)
/ttlltUUMtttttltltlUHIttll ************ ttttmtiitiiu)
/» Главная функция, в «порой устанавливаются все адреса,»/
/* заменяется прерыванве » програина остается резндевтом »/
/*****«****************************»»**»*****»************/
®ain()
[ unsigned ue»_sise - (_SP/16L) t 1; /» так нокно вичес-
лить размер (nes.sise) просраш в параграфах »/
video - (disp far »)ОкВ8000000; /« установка указатеи
video la лачауо области stpaiioi паннтл »/
sh = (key huge *)0x417; /» установка указателя sh sa
переиенув BIOS по адресу 0:0417 »/
old = (intjn »)getvect(0x9); /» в переиеввой old сох-
раняется точка входа в оригииаяьвув програииу BIOS
для обработки прерцзавия 9 »/
setvect(0x9,new); /» теперь деваиА вектор будет указы-
вать ла налу программу пел »/
keep(0,»es_siBe); /» выполняется указанне ла заверленле
программы и сохранение ее резидентом »/
)
Текст программы наполнен содержательными комментариями, поэтому
ограничимся лишь перечислением того, что нужно сделать для получения
работающего модуля:
1) установить минимальную модель памяти Tiny (см. гл. 9);
2) получить загрузочный модуль программы (нажать клавишу F9),
но ire выполнять его в среде ТУРБО СИ (предупреждение компонов-
щика по stack для модели Tiny не свидетельствует об ошибке, и его сле-
дует игнорировать);
3) выйти в сред)' ОС;
4) преобразовать EXE файл в СОМ файл с помощью утилиты
EXE2B1N (см. гл. 3);
5) выполнить полученную резидентную программу типа СОМ.
В заключение приведем пример программы (написанной на языке
ассемблера), полностью подменяющей стандартную процедуру BIOS,
вызываемую через девятый вектор (ввод скэн-кодов от клавиатуры,
преобразование их н размещение во входном циклическом .буфере).
Все то, что должна делать эта программа, описано в § 2.1. Она выполняет
ограниченное число функций, но дает все необходимое для создания
любых законченных модулей подобного типа. Переключение русского
и латинского алфавитов осуществляется с помощью клавиши Caps-
Lock (ФПБ). Прописные буквы будут появляться на экране при удер-
живании в нажатом состоянии клавиш Shift ^слева или справа. Ос-
тальные режимы модифицирующих клавиш, поддерживаемые процеду-
рой BIOS, в программе не реализованы. Ниже приводится пример:
.MODEL SMALL ; объявление налой иоделн
.DATA ; еегыент данных
j*»»»*»»»»*»*»»»*»»»»»»****»»*»»»»*»**»»»»»»»»»»»;
; Таблица кодов сннзолоз ди латинского алфавита ;
; (каждая строка соответствует линии клазки на ;
; клавиатуре) ;
;**»»»*****»»»*»******»»»»*****»*:»»»*****»»*****»;
KODL DB 0,27,'1234567890-:',8,9
DB 'qwertyuiopE ]’,13,0
DB 'asdfghjkl:',39,92,0,0
DB 'яхсуЬпе,./',0,0,0,32,0, 67,66,65
SB 9 DSP (0)
418
DB '789-456*1230.',О
DB 0,27,'.'wW4»()_*',8,9
DB WTYOIOPO' ,13,0
DB '4SDFGHJKL:e!',0,0
DB 'ZXCVBNHo!',0,0,0,32
DB 13 DDF (0)
DB '789-456*1230.',0
;»»»«»»»,»»»»»»»»»»»>»»»»»«»»»»»♦»»»»»»»»»»»»»»;
; Таблица кодов стоки ди русского алфавита ;
jlltmtlttilltmiilUltlilttUtttllliKUIttl;
KODH DB 0,27,'1234567890-:',8,9
DB 'йцукенгацзхъ',13,0
DB 'Фивапролдхэ;',13,0
DB 'нсипбвё',0,0,0,32,0, Каф. 3 8 К',0,0
DB '789-456*1230.',0
DB 0,27,'Скляров В.А.',8,9
DB 'ВДУШГЦЗП'ЛЗ.О
DB 'ИМПРОШЭ:',0,0
DB 'ЯЧСМИТЬБЮЙ'.О.О.О.Зг.О.'Иннск РТЯ',0,0
DB '789-456*1230.',О
.STACK ЗОВ ; раздел стека
.CODE ; сегмент кода
init РИОС near ; начало процедуры init
;»»»»»»»»»»»>»»»МИ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
; Замена девятого вектора прерывания (новый вектор ;
; указывает на точку входа в програниу nen_vect) ;
;»»*»»>»»»»»»»«»»»»»»»»»»»»»»»»»»»»»»» »»»»<»»»»»»»<:
сП ; установка запрета врерызаннй
push ds ; сохранение ds в стеке
вот ах, seg new_vect ; установка ds:dx на точку
шоу ds,ах ; входа в программу nes.vect
sov dx,offset new_vect
bov al,9 ; замена девятого вектора
aov ah,250 ; Функция 25В прерывании 21В ус-
int 21H ; таназлнзает вектор прерывания
pop ds ; чтение ds мз стека
sti разрешение прерываний
; Функции 31В прерывании 21В обеслечввает зазермение ;
; нрограмми s сохранение ее резядентои ;
bov dx,80 ; з dx объем програнин з параграфах
нот ah,31В
int 218
init endp ; конец процедуры init
; Процедура ne«_vect будет работать вместо орограмнп BIOS ;
; для обработкв аппаратного прерывания от клавиатуры ;
;UUUUU »»»»»»«»»»»,»»»»,»»;
oe«_vect PROC PAR ; начало процедуры пеи.тес!
push ах ; сохранение нзиениеиых регвстроз а стеке
push Ьх
push сх
push di
push es
push ds
; Чтеняе скзн-кода н звдача сигнала, подтверхдавцего ;
; его прием ;
419
in al,60В ; чтение скэн-кода
aov ah,al ; сохранение скэн-кода в ah
bov bi,ax ; сохранение ах в Ьх
in al,61H ; чтение a al байта нз порта 618
or al,80H ; запись 1 а седьной бнт байта a al
out 61H,al : запись измененного байта а порт 618
and al,7fH ; запись 0 а седьной бнт байта a al
out 61B,al ; запись изиеиенного байта а порт 618
»»»»»»»»;
; Установка регистра ES на начало области данных BIOS ;
• ov ах,IBS ; запись а ах сегкентного адреса области
; переменных BIOS
• ov es.ax ; пересылка ах a es
; Проверка нахатня клавнин "сдиг слева" ;
»»»»««;
• ov ах,Ьх : пересылка а ах значения Ьх (сохранено
: ранее)
свр al,42 ; проверка наличия a al екэк-кода клазпии
; "сдвиг слева"
jne kJ. ; есдн такого кода нет, то переход к kJ,
• ov Ы,1 ; а противном случае а bl записывается едл-
ог ез:(17В],Ь1 ; ница, н она засылается а байт 0:0417
j«P quit ; переход на ветку quit
; Яроаерка отпускания клавипн "сдвиг сдеаа” ;
; »»»»»»»НН»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
kJ: с«р al, 170 ; проверка отпускания клавиия
jne next ; если нет, то переход к next,
• ov bl.OfeB ; если да, то сброс нулевого бита
and es:[178],bl ; а банте 0:0417 ‘
jw quit ; переход на метку quit
j»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
; Проверка накатпя клазиии "сдвиг справа" ;
;»»»»»»«»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
next;c«p al,54 ; сдедуцне пять строк аналогичны
jne k_r ; предыдуянм, но проверяется нада-
ют bl,2 ; тие клавини “сдаю справа"
or es:[178],bl
j>p quit
пм^шшнттнттнштттт-,
; Проверка отпдсканп клавиии "сдвиг справа" ;
j»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»;
k_r: cap al, 182 ; сдедуцне пять строк аналогичны
jne Capslock ; вредыдуиии, но проверяется отпус-
mv bl.OfdB ; канне клазиии "сдвиг свраза"
and es:[178],bl
jap quit
j»»»»»»»»»»»»»»»»»»»»,»,»»»»»»,,,»»»,»»;
; Проверка надатнн кдаанлн "Caps-lock" ;
;**************************************-
Capslock:
ov bl,es:(170] ; если кдаанаа Caps-lock была палата
test bl,408 ; ранее s снова поступает ее скэи-код,
jna doen ; то иестой бит байта 0:0417 додден
; бить устанозлеп а нуль
свр al,58 ; если Caps-lock не надата н вос-уинл
420
jce зхв ; вот bl,40S ; or ея:(1ТВ],Ы ; jap quit ; не ее скан-код, то вереход к sib есхг Caps-Lock не наката г поступил ее скэн-код, то устанавлввается 6-й бвт байта 0:0417, в осуществляется переход к quit
; Проверка повторного вахатвя кшнев "Caps-Lock" ;
domrsov bl.es: (17Н] ; есхг Caps-Lock не нахата ранее,
test bl,408 ; то переход к метке sii
jz sis свр al,58 ; если Caps-Lock наката в поступил ее
Sue sii ; скэн-код (58), то обнуляется иестой
iov bl.ObfB ; бвт банта 0:0417 н осуцествхяетсг
aud es-.imj.bl ; jap quit переход к метке quit
;1ППШШШПШШПП1П, ; Проверка отвусканвя kubhie ; ;ПППипииии»ПП«тП;
sii: test >1,800 ; лроверяетсЕ отпускавве кшеве
juz quit ; еслн отпускаяве, то период к quit
; Пронерка нанатвя на иавнву сдвига (справа eim слева) ; ;пшпипплиппишп1ш>п»шшишпшп»;
1OV Ь1,ез-.(1Т8] test Ь1,3 ; eciE не канаты kubese 'сдвег справа1
jz decod ; ми ’сдвег схева", то вереход ва метку
add al,85 ; decod, вначе к al добавявется 05 дхя выбора проввсвих букв
; Еслв бих акхвчег рехгв Caps-Lock, to декодируется табхгца ; , KODH с русскгнв буквам», а есхг ог викпчен, то табхгца •,
; KODL с латггскгиг буквами ;
;***********************************************************;
decod:
bov bl,es:[170] ; в завгсввося от значения вестого
test bl,408 ; бита в байте 0:0417 выбирается
jz tabl ; таблица KODR или KODL
iov bx.seg KODR ; в ds записывается сегиентннй адрес
iov ds,bx ; таблица перекодирования
bov bx,offset KODR ; в Ьх устанавливается смещение ', таблицу перекодирования
xlat KODR ; в al возвращается ASCII-код
cap al,0 ; если он равен нуле, то переход
je quit ; к метке quit
jup buf ; иначе переход к ветке buf
tabl:
iov bx,seg KODL ; схедущве весть строк подобны
bov ds,bx ; вредыдущим, во работает с
bov bx,offset KODL ; таблицей KODL
list KODL
rap al,0
je quit
;»>>>>>»>>>>>»»>>>>>>><>>>>>»>>>>»>>>>»>>;
; Проверка буфера клавиатура на переполневие ;
buf.tov bx.laS ; в ex читается свелеиие дхя
вот cx.es:[bx] ; качала буфера кхавиатури
bov di.es:(bxtSJ ; в di - аецеиве дхя конца буфера
421
свр сх.ЗсН
je spec
inc cz
inc ex
cap ex,di
je quit
JEP g_3
зресгстр di,leS
je quit
; если сх на верхней границе, то
; переход на метку spec
; иначе два раза сх увеличивается
; на единицу
; усювие того, что буфер полон,
; переход на метку quit
; переход к метке для запнси сммвоха
; если di в начале буфера, то он
; заполнен (переход к quit)
; Запись символа в буфер клавиатуры ;
g_5;B0v es:(di],ax ; екзн-код и ASCII-код записывается
; в буфер
cap di,3cH если di не в конце, то его
jne uoji ; значение увеличивается на 1.
bov di,28 ; иначе на 28 + 2
пол: add di,2 ; увеличение di на 2 нлн на 28+2
hoy es:(bx]+2,di ; изменена смецения дхз ловца буфера
; Завершение прерывание ;
quit: pop ds ; восстановление стека
pop es
pop di
pop ex
pop bx
boy al,20H ; разрежение прерываний более
out 20M1 ; низкого приоритета
pop ах
iret ; восстановление CS:IP и регистра флагов
new_vect eodp ; конец процедуры ne*_vect
Ш ; конец программы
12.3.3. Прерывания для управления дисплеем,
клавиатурой и принтером
Обслуживание дисплея нижнего уровня осуществля-
ется через прерывание 16 (lOie). При его описании пред-
полагается, что ПЭВМ снабжена дополнительным ПЗУ
BIOS (см. § 2.2), обеспечивающим расширение возмож-
ностей видеосервиса для адаптеров EGA/VGA. Как и в
случае вектора 26 (1А,в), прерывание 16 объединяет раз-
личные функции. Дадим их краткую характеристику.
установка режима отображения (АН=0) — на входе:
AL— номер режима, который может принимать значения,
перечисленные в первом столбце табл. 2.2. Дополнительно
укажем размер матрицы для отображаемых символов
[20]. Ниже после соответствующей матрицы в скобках
перечислены через знак / (косяк) шестнадцатеричные
номера режимов и типы адаптеров: 8X8 (0/CGA, 2/CGA,
3/CGA, 4/CGA/EGA/VGA, 5/CGA/EGA/VGA, D /
CGA/EGA/VGA, E/CGA/EGA/VCA, 13/VGA); 8Х 14 (О/
422
EGA, 1 /EGA, 2/EGA, 3/EGA, 6/CGA/EGA/VGA, F/CGA/
EGA/VGA, 10/EGA/VGA); 9X16 (О/VGA, 1/VGA, 2/
VGA, 3/VGA, 7/VGA); 8X 16 (11/VGA, 12/VGA);
установка размера курсора (AH= 1) — на входе:
CH — номер начальной линии для курсора в диапазоне от
Одо 31 (если 32, то курсор пропадает); CL — номер конеч-
ной линии для курсора (от 0 до 31);
установка курсора в заданную позицию (АН=2) —
на входе: ВН — номер видеостраницы; DH — номер стро-
ки; DL— номер позиции в строке (начиная с 0);
чтение позиции и размера курсора (АН=3) — на вхо-
де: ВН — номер видеостраницы; на выходе: DH, DL —
номер строки и номер позиции в строке; CH, CL — номера
начальной и конечной линий курсора;
чтение данных о световом пере (АН= 4) — на выходе,
если АН=0, то отсутствуют данные; при АН= 1 — дан-
ные считаны; DH, DL — строка в позиции символа в тек-
стовом режиме; СХ, ВХ — строка и позиция точки в гра-
фическом режиме;
задание активной страницы экрана (АН=5) —на
входе: AL— номер выбираемой страницы;
перемещение окна экрана вверх или очистка окна
(АН= 6) — на входе: CH, CL — строка и позиция верхне-
го левого угла окна (начиная с 0); DH, DL — строка
и позиция нижнего правого угла окна; AL — число строк,
на которые осуществляется перемещение; ВН — атрибут
для пустых строк;
перемещение окна экрана вниз (АН= 7) — аналогич-
на предыдущей функции;
чтение символа и его атрибута из текущей позиции
курсора (АН =8) —на входе: ВН—номер видеостра-
ницы; на выходе: AL— прочитанный символ; АН — атри-
бут символа (только для текстового режима);
запись символа и его атрибута в текущую позицию
курсора (АН=9) — на входе: ВН —номер видеострани-
цы; AL — символ для записи; СХ — число повторений
вывода символа; BL — атрибут (если в графическом ре-
жиме добавлено 8016, выполняется операция Исключаю-
щее ИЛИ с символом на экране);
запись символа в текущую позицию курсора (АН =
= 10) — аналогична предыдущей функции, но без анализа
регистра BL;
задание цвета палитры или бордюра для адаптера
CGA (АН= И) — на входе: если ВН=0, указать в BL
цвет бордюра в текстовом режиме; если ВН= 1 и BL=0,
423
выбирается палитра 0; если ВН= 1 и BL = 1, выбирается
палитра 1 (см. § 2.2);
запись графической точки (АН= 12) — на входе:
ВН — номер видеостраницы; DX, СХ — строка и позиция;
AL—номер цвета (добавление 80^ означает операцию
Исключающее ИЛИ с точкой на экране); .
чтение графической точки (АН= 13) — на входе:
ВН — номер видеостраницы; DX, СХ — строка и позиция;
на выходе: AL — номер цвета считанной точки;
запись символа на активную видеостраницу (АН =
= 14) —на входе: AL — символ; BL — цвет переднего
плана;
считывание номера текущего режима (АН= 15) —
на выходе: AL—номер текущего режима (см. функ-
цию 0); АН — число символов в строке; ВН — номер
текущей активной дисплейной страницы;
видеосервис EGA/VGA (АН= 16, АН= 17, АН =
= 18) — включает много подрежимов и рассматривается
далее отдельно;
запись строки для EGA/VGA (АН= 19) — на входе:
ES:BP—указатель на выводимую строку; СХ — длина
строки; DH, DL — строка и позиция начала вывода; ВН —
номер видеостраницы; AL= 0 — использовать атрибут
в BL без перемещения курсора; AL= 1 — использовать
атрибут в BL с перемещением курсора в конец строки;
AL= 2 — использовать двухбайтный формат строки (сим-
вол и атрибут) без перемещения курсора; AL= 3 —
то же, что и AL=2, но с перемещением курсора в конец
строки;
сохранение/восстановление различной информации
для видеодоступа EGA/VGA (АН=28) — на входе:
AL=0— возвратить размер буфера; AL= 1 — сохране-
ние; AL= 2 — восстановление; СХ= 1 — состояние видео-
оборудования; СХ=2 — область видеоданных; <ЗХ=4—
режимы и регистры цвета; ES:BP— указатель на буфер;
на выходе: AL= 28—нормальное завершение; ВХ —
размер буфера для AL=0.
Рассмотрим подфункции для видеосервиса EGA/VGA.
Начнем с АН= 16 (101б):
установить регистр палитры — на входе: AL=0;
BL—номер регистра; ВН—значение регистра (цвет);
установить регистр бордюра — на входе: AL= 1;
ВН —значение регистра (цвет);
установить все регистры палитры и регистр бордюра —
на входе: AL=2; ES:BX—указатель на 17-байтную
424
область памяти со значениями кодов для регистров
палитры (их 16) и бордюра;
выбрать интенсивность или мерцание — на входе:
AL= 3; BL — 0 — интенсивность фона; BL= 1 — мерца-
ние;
читать регистр палитры (только для VGA) — на входе:
AL= 7, BL — номер регистра; на выходе: ВН — значение
регистра;
читать регистр бордюра (только для VGA) — на вхо-
де: AL= 8; на выходе: ВН — значение регистра;
читать все регистры (только для VGA) — на входе:
AL=9; ES:DX — указатель на 17-байтную область, в ко-
торую должны заноситься значения 16 регистров палитры
и регистра бордюра; на выходе: данные, записанные
в выделенную область памяти;
установить регистр цвета (только для VGA) — на вхо-
де: AL= 16; ВХ — номер DAC регистра (см. § 2.2); СН,
CL, DH — шестибитовые коды интенсивностей зеленого,
синего и красного цветов для выбранного DAC регистра;
установить множество регистров цвета (только для
VGA) — на входе: AL= 18; ВХ — номер первого регистра;
СХ — число регистров; ES:DX—указатель на таблицу
значений для регистров, элементы которой включают
последовательности кодов интенсивностей (в таком виде:
красный, зеленый, синий, красный, зеленый, синий и т. п.);
выбор страниц для цвета (только для VGA) — на
входе: AL= 19; BL=0—4 страницы и 64 цвета; BL=0;
ВН= 1—16 страниц и 16 цветов; BL= 1; ВН—число
страниц для цветов;
чтение DAC регистра (только для VGA) — на входе:
AL = 21; ВХ— номер DAC регистра (см. § 2.2); на выхо-
де: CH, CL, DH — интенсивности зеленого, синего и крас-
ного цветов;
чтение множества DAC регистров (только для
VGA) — на входе: AL= 23; ВХ — номер первого DAC
регистра; ES: DX — указатель на таблицу для сохранения
полученных значений; на выходе: заполненная таблица
(см. также AL= 18);
чтение номера текущей страницы цвета (только для
VGA) — на входе: AL= 26; на выходе: ВН — текущая
страница; BL — режим;
смешивание цветов (только для VGA) — на входе:
AL= 27; ВХ— номер первого регистра; СХ—число ре-
гистров. Здесь производится чтение RGB значений из
регистров, которые преобразуются следующим образом:
425
30%R + 59%G + 11 %B. Полученный результат переписы-
вается в регистры.
Далее рассмотрим подфункции для АН= 17 (1116),
которые обеспечивают различные режимы работы со
шрифтами:
загрузка шрифтов пользователя с общим сбросом
видеоокружения—на входе: AL=0: BL—номер блока
для загрузки от 0 до 4 (см. § 2.2): ВН — число байтов на
символ; СХ—число символов; ES:BP—указатель на
таблицу пользователя; DX— смещение символа (шрифт
загружается, начиная с этого ASCII-значения);
загрузка символов с матрицей 8Х 14 и с ПЗУ с общим
сбросом вндеоокружения — на входе: AL= 1; BL — номер
блока для загрузки;
загрузка символов с матрицей 8X8 из ПЗУ—на
входе: AL = 2; BL—номер блока для загрузки;
установка блоков — на входе: AL=3; BL — значения
для двух блоков (от 0 до FF16). В § 2.2 говорилось про
регистр 3 порта ЗС516, у которого биты 3—2 и 1—0 указы-
вают номера двух блоков. Эти значения и задаются в BL
(предварительно следует выполнить подфункцию АХ =
= 100016, ВХ= 071216 [20]);
загрузка символов с матрицей 8X16 из ПЗУ — на
входе: AL=4; BL— номер блока для загрузки;
загрузка шрифта пользователя — на входе: AL= 16;
все остальное, как у подфункции с AL= 0;
загрузка символов с матрицей 8X14 из ПЗУ — на
входе: AL= 17; все остальное, как у подфункции с AL =
= 1;
подфункции с AL= 18 и AL= 20 подобны подфункциям
с L= 2 и AL= 4;
загрузка шрифта пользователя для второй полови-
ны таблицы ASCII — на входе: AL=32; ES:BP — ука-
затель на таблицу пользователя для кодов ОТ 128 до
255 (на такую таблицу указывает вектор прерывания
1F,6);
загрузка шрифта пользователя — на входе: AL = 33;
BL= 1 — 14 строк на экране; BL= 2—25 строк на экране;
BL=3—43 строки на экране; СХ — число байтов на
символ; ES:BP—указатель на таблицу пользователя
для всех графических символов (на такую таблицу указы-
вает вектор 44,б);
загрузка символов с матрицей 8X14 из ПЗУ — на
входе: AL=34; BL= 1 —14 строк на экране; BL = 2—25
строк на экране; BL=3—43 строки на экране;
426
загрузка символов с матрицей 8Х 8 из ПЗУ — на вхо-
де: AL=35; все остальное, как для AL=34;
загрузка символов с матрицей 8Х 16 из ПЗУ — на
входе: AL=36; все остальное, как для AL=34;
получение информации об установленных режимах —
на входе: AL=48; ВН=0—возвратить в ES.BP ука-
затель на таблицу шрифтов (на нее указывает вектор
lFi6); ВН= 1 — возвратить в ES:BP указатель шрифтов
(на нее указывает вектор 4416); ВН=2— возвратить
в ES:BP указатель на таблицу шрифтов ПЗУ с матрицей
8X14; ВН= 3—аналогично ВН=2, но матрица 8X8;
ВН=4 — аналогично ВН=3, но указатель на 128-й сим-
вол таблицы; ВН=5—аналогично ВН=2, но матрица
9Х 14; ВН=8— аналогично ВН=2, но матрица 8Х 16;
ВН=9 — аналогично ВН=2, но матрицы 9Х 16; на вы-
ходе: СХ — число байтов на символ; DL — число строк
экрана минус единица; перечисленные выше значения
ES:BP.
В заключение рассмотрим подфункции для АН= 18
(1216):
получение информации об адаптере — на входе: BL =
= 16; на выходе: ВН = 0 — цветной режим; ВН= 1 —
монохромный режим; BL — объем экранной памяти (0—
64 К байта, 1-128 К байт, 1016—192 К байта, 11)(, —
256 К байт); CL—установка переключателей (все их
значения перечислены в работе [20]);
установка альтернативного режима печати (для 43
строк на экране) — на входе: BL=32;
выбор числа линий сканирования (только для VGA) —
на входе: BL — 48; AL = 0—200 линий; AL= 1—350 ли-
ний; AL= 2 — 400 линий;
загрузка регистров палитры при установке режимов
(только для VGA) — на входе: BL — 49; AL= 0 — разре-
шение загрузки; AL= 1 — запрет загрузки;
разрешение/запрет видеодоступа (только для VGA) —
на входе: BL=50; AL=0 — разрешение; AL= 1 — за-
прет;
разрешение/запрет смешивания ' цветов (только для
VGA — на входе: BL=51; AL=0—разрешение; AL =
= 1 — запрет;
эмуляция курсора (только для VGA) — на входе: BL =
= 52; AL=0— разрешение эмуляции; AL= 1 — запрет;
две последние подфункции (BL= 53 и BL= 54) исполь-
зуются только для VGA и связаны со спецификой работы
дисплея.
427
Приведенная ниже программа иллюстрирует некоторые приемы
работы с прерыванием 16:
(include <stdio.h>
finclude <dos.h>
linclude <conio.h>
tain!)
( int i,str,poz,start,kon.ob;
clrscr(); /< очистка экрана »/
/< удакнне курсора - функция 1 (_АЬ-1}, _СН=20 »/
JBM; _СВ=0к20;
geninterrupt(OslO); /< вызов прерыванвя flslfl </
/» нзкененне в цикле размеров курсора »/
for(i=0;i<0xlf;itt)( delay(lOO); /< задержка </
_АВ=1; _сВ=0лй; /< _С8 - начальная лвиня дн курсора </
/< _С1 - конечная лнннн ш курсора </
geninterrupt(0x10); )
/» установка курсора в 20-в позицию 10-й строки </
_АВ=2; /< функции перемецення курсора «/
JB=0; /< нонер видеостраницы »/
JB=10; Jl=20; /< 10-я строка; 20-н позкцня </
geninterropt(OxlO); delay(2000);
puts("larsH-e любую клазиву*); getcb();
_АВ=3; /» функций Alt чкннн позиции курсора V •
_ВВ=О; /» нонер видеостраницы Ч
geninterrupt(0x!0);
str=JB; poz=Jl; start-.CB; kon=_Cl;
printf("X курсора: Id; У курсора: Sd;Кпначальнай '
"ihhhh курсора: id; конечная лнння курсора:"
Id.\n", str,рог,start,kon); getch();
/< переиеценне текста вверх (_АВ=6) на 5 позяцнй </
_АВ=6; _СВ=0; _CL-0; JB=18; _Cl=70; JB=0; JL=5;
geninterrupt(OxlO); getch();
/< оеренененне текста аннз (JBcjO) на 10 позиций »/
-ЛВ=7; -СН-0; -С1=0; JB=18; _Cl‘-70; _ВВ=О; JU10 :
geninterropt(OxlO); getchf);
/» вывод нерцаю^ей строки с 55-в ирочерканн »/
J!f=0x9; JU,:"-'; _£Х=55; _В8=0; JUOxOT;
geninterrupt(OzlO); getch();
/» установка норшьного рехнма отобрахеннн сннвоков »/
_АН=0х9; JU,:'-'; _£Х=55; _ВН-0; Л=0х7;
gen interrupt!0x10);
JB=2; _2U=0; _DB=5; J)l=10; geninterrupt (Ox 10);
/» определение ойека оперативной оанин ПЭВМ »/
geninterrupt(0x!2); ob=_АГ, *•
printf("Объем оперативной памяти ПЭВМ: Ш К байДп’.оЬ);
/» определение объема расвнренной памяти ЕЭВН »/
_ВВ=0х88; geninterrupt(0x15);
ob=_AX; ..и
printf("\t Объем расвнренвой памити; Id К байт\п".oh):
geninterrupt(S); /» распечатка экрана </ )
Сначала в ней удаляется курсор. Затем через промежутки времени
0,1 с показываются его возможные размеры. После этого устанавли-
вается и считывается местоположение курсора, осуществляются раз-
личные перемещения текста, выводится мерцающая строка из 55 про-
черков, определяется объем оперативной и расширенной памяти ПЭВМ.
Последний вычисляется с помощью функции 88,6 прерывания 21 (15ie)
и имеет смысл только для машин с расширенной памятью. Вычисление
428
объема основной оперативной памяти осуществляется с помощью
прерывания 18 (12,6). Полученная величина (в килобайтах) возвра-
щается в регистр АХ. Последняя строка программы содержит обращение
к прерыванию 5. В результате содержимое экрана будет распечатано
на принтере.
Следующая программа демонстрирует вывод на экран текста
одновременно двумя шрифтами (см. также § 2.2), при этом одновременно
может быть отображено 512 различных символов:
•include (stdio.h)
I include (string.h>
linclode (dos.h)
void nain()
( unsigned char >strl, *str2;
strl - "lout HI: 0 1 2 3 4 5 6 7 8 9';
str2 "Font H2: 0123456789";
_A8 - 17; Jt 2; /» функции 17, подфункции 2 »/
Jt - 1; /4 внбор блока 1 »/
geninterruptf 16); /» пазов орериваш 16 »/
JB - 17; Jt - 3; /» функций 17, подфункция 3 »/
Jt - 4; /» вабор бхош 1 и 0 */
geninterruptf16); /» вязов прерывании 16 »/
/штнхххшнипхшхшиших/
/* Строка 1 вычерчивается ирифтои 1 Ч
Л - strlen(strl);/» в СХ заносится дина строки strl »/
JX 0x710; /» 16-я позацнн, 7-а строка »/
JS - JS; /» в 8SJP заноснтси указатекь Ч
JP - (unsigned)strl; /» на начадо строки strl »/
_АВ - 19; /» внбор функции 19 »/
JX - ОхВ; /» в бите 3 дан атрибутов 1 Ч
Л - 1; /» перекестап курсор в конец строен Ч
geninterrupt(lfi); /» внзов прерывании 16 »/
/* Строка 2 вычерчивается «рифтом 2 »/
Л - strlenlstr2); /» ниже выподкяптсн аналогичные »/
Л - 0x010; /4 действии jn str2 »/
JS - JS;
JP - (unsigned)str2;
_АЙ = 19;
JX = 3; /* в бете 3 Jia атрибутов 0 »/
Л = 1;
geBinterrupt(16); /» внзов прераваиия 16 Ч
)
Обслуживание клавиатуры нижнего уровня осущест-
вляется через прерывание 22 (16iB). При этом выделены
следующие функции:
чтение очередного символа (АН= 0) — программа
приостанавливает работу и ожидает нажатия клавиши;
на выходе: AL — ASCII-код введенного символа (если
AL= 0, то нажатой клавише соответствует расширенный
ASCII-код); АН — скэн-код или расширенный ASCII-
код;
проверка нажатия клавиши (АН=1) —на выходе:
429
ZF=O, если клавиша нажата, и ZF—1— в противном
случае; АХ — как для АН= 0;
чтение состояния модифицирующих клавиш, таких, как
Shift, Caps-Lock и др. (АН=2) —на выходе: AL —
состояние модифицирующих клавиш.
Обслуживание принтера на нижнем уровне осущест-
вляется через прерывание 23 (17ie). Здесь выделены
следующие функции:
печать символа (АН= 0) —на входе: AL — ASCII-
код подлежащего печати символа; DX — номер принтера
(0, 1 или 2); на выходе АН= 1, если символ не может
быть отпечатан (см. также функцию АН=2);
инициализация (установка в начальное состояние)
принтера (АН= 1) — на входе: DX — номер принтера
(0, 1 или 2); на выходе: АН — состояние принтера (см.
функцию АН=2);
получение информации о состоянии принтера (АН =
= 2) — на входе: DX —номер принтера (0, 1 или 2); на
выходе: АН — состояние принтера (бит 0 — ожидание, би-
ты 1,2 — не используются, бит 3 — ошибка ввода-вывода,
бит 4 — выбор (0— нет подключения), бит 5 — отсутст-
вие бумаги, бит 6 — подтверждение, бит 7 — отсутствие
готовности (1 — свободен, 0— занят)).
Приведенная ниже программа иллюстрирует основные правила
работы с прерываниями 22 (16ie) и 23 (1716); дополнительно в ней
использовано обращение к прерыванию 27 (1Ви,), осуществляющему
выход из программы по УПР — СТОП (Ctrl — Break):
•include <dos.h>
•ain()
( unsigned int ascii,scan,sh,i; char si>;
puts("Введите симвоГ);
/х чтение ASCH- и скэн-кодое »/
_А8:0; genintempt(0x16);
ascii=JI; scan=ascii/256; ascii 8= Oxff;
if(ascii=-O)
printf СРаянренний ASCII-код: Id An', scan);
else printf fiSCII-xog: Id; cm-ход: Id.\n‘,
ascii,scan);
/» состояние иоднфнцнрувжях клавни х/
_AH-2; geninterrupt(0x16); sh=_AL;
printf('состояние иодифяцаруялнк навил: Id\n",sh);
puts("Cmeoi Jis вывода на печать (Х-хонец)?');
scanf(‘Ic",8si«); /» если sit:'»', то крерыванке
во Ctrl-Break */
/» крерывание работы ирограииы во Ctrl-Break х/
if(si>=:'x') geninterrupt(27);
/« еывод на печать 70 снпвоюе sii >/
f or (b0;i<70; itt)
1 _AH-O; jhesis; JfcO; geninterrupt(0x17); ) )
430
12.3,4. Прерывания для работы с накопителями
на магнитных дисках и коммуникационным адаптером
На нижнем уровне обслуживание накопителей на
гибких магнитных дисках осуществляется через пре-
рывание 19 (13ib). В него входят следующие функ-
ции:
начальная установка (рекалибрация) дисковода
(АН = 0) — на входе: если DL— 80^ или DL= 81^, выби-
рается контроллер жесткого диска (винчестера); в против-
ном случае — контроллер гибкого диска;
выдача текущего состояния дисковода (АН= I) — на
входе: при DL<80ie — с гибкими дисками; при DL>
>7Fib — с жесткими дисками; на выходе: AL — код
ошибки (статус диска);
чтение группы секторов с одной дорожки (АН=2) —
на входе: DL — номер дисковода (0—гибкий диск А,
1 — гибкий диск В и т. п., 8016 — первый винчестер, 8116 —
второй винчестер и т. п.); DH —номер головки записи/
чтения (номер стороны диска); СН — номер дорожки или
цилиндра (начиная с нуля); CL — номер сектора (начиная
с единицы); AL— число секторов (не более чем на одной
дорожке или цилиндре); ES:BX — указатель на буфер
с прочитанными данными. Если произошла ошибка при
чтении, будет установлен в единицу флаг CF в регистре
признаков (при этом код ошибки помещается в АН). За-
метим, что в CL номер сектора занимает младшие 6 бит,
а старшие два бита используются как старшие два бита
номера цилиндра;
запись группы секторов на одну дорожку (АН=3) —
на входе те же данные, что и для функции АН= 2,
ES: ВХ — указатель на буфер, из которого осуществляется
передача данных надиск; на выходе: CF= 1, если произо-
шла ошибка записи (ее код в АН);
проверка секторов после записи или чтения (АН= 4) —
входные и выходные данные здесь те же, что и для преды-
дущих двух функций;
форматирование дорожки (АН= 5) — на входе: DL —
номер дисковода; DH — номер стороны; СН — номер до-
рожки; ES:BX — указатель на буфер с данными о режиме
форматирования, который включает последовательность
блоков из четырех байтов каждый: первый байт — номер
дорожки (цилиндра), второй — номер стороны, третий —
номер сектора, четвертый — размер сектора (0—128 байт,
1—256 байт, 2—512 байт, 3—1024 байта); подробности
о заполнении блоков даны в приведенном далее примере;
431
на выходе; если CF = 1, то при форматировании произош-
ла ошибка (ее код в АН);
выдача текущих параметров накопителя (АН=8) —
на входе: DL — номер дисковода; на выходе: DL —
число жестких дисков для первого контроллера; DH —
число головок; СН — число цилиндров; CL — число секто-
ров (два старших бита относятся к числу цилиндров,
как и в функции АН = 2);
инициализация параметров диска (АН= 9) —сообща-
ет BIOS о любом изменении таблиц параметров устройства
(у модели АТ векторы 4116 и 46ie адресуют эти таблицы
для твердых дисков 0 и 1; в случае XT используется вектор
40 |б);
длинное чтение данных (АН— 10) — на входе те же
значения, что и для функции АН= 2; на выходе: ES:BX —
буфер, где содержатся данные сектора (512 байт) плюс
4 байта. Таких блоков будет столько, сколько секторов
задано в AL. При ошибке устанавливается в единицу
CF (ее код в АН);
длинная запись данных (АН=11)—аналогична
предыдущей функции, но производится запись дан-
ных;
перемещение головки к нужной дорожке (АН= 12) —
на входе: DL, DH, СН — номера диска, стороны и дорож-
ки; на выходе: CF, АН, как в предыдущих функциях;
альтернативный сброс устройства (АН= 13) — на
входе: DL— номер диска;
чтение данных в буфер (АН= 14) — на входе те же
данные, что и для функции АН=2; на выходе: CF, АН,
как в предыдущих функциях;
запись данных из буфера . (АН= 15) — на входе
и выходе те же данные, что и для предыдущей функции;
проверка готовности диска (АН= 16) — на входе:
DL—номер дисковода; на выходе: АН—'состояние
дисковода;
калибровка диска (АН= 17) — на входе: DL — номер
дисковода; на выходе: АН — состояние дисковода;
диагностика памяти контроллера (АН= 18) — на вы-
ходе: АН — состояние дисковода;
диагностика дисковода (АН= 19) — на выходе: АН —
состояние дисковода;
внутренняя диагностика контроллера (АН= 20) —
на выходе: АН - - состояние дисковода;
выдача типа накопителя (АН= 21) — на входе: DL —
номер дисковода; на выходе: АН — код дисковода (0 —
132
дисковод не существует, 1,2 — гибкие диски, 3 — жесткие
диски);
чтение статуса замены диска (АН= 22) — на выходе:
АН= 0 — диск не был заменен; АН= 6 — открыт диско-
вод; DL — номер заменяемого диска;
установка типа накопителя (АН= 23) — на входе:
DL — номер дисковода (0 или 1); AL — тип диска (0 — не
используется, 1 — дискета 360 К байт, дисковод
360 К байт, 2 — дискета 360 К байт, дисковод 1,2 М байта;
3 — дискета 1,2 М байта, дисковод 1,2 М байта). Эта
функция используется перед операцией форматирования.
Ниже приводится программа, показывающая основные правила
работы с отдельными функциями прерывания 19 ( 13ib):
linclude <dos.h> /4 работа с врерывавмеи 19 »/
•ain()
[ char str[512J; int i;
/« запмвевве буфера хая форматирования цша »/
char ms[J - ( 4,0,1,2,4,11,2,2,4,0,3,2,4,0,4,2,4,0,5,2,
4,0,6,2,4,0,7,2,4,0,8,2,4,0,9,2 J;
/» 4-в дорохха; О-в норова; 1-й сегмент; 512 байт
в сегмевте в т.п. »/
/» установка двсковода в вачальное состояние (JB=0) »/
JB’-O; Л=0;
geninterrupt(0xl31; /» вызов врерывавмя 0x13 »/
/» функция 0x17 выбирает двсховод О (Л=0) я умаиавквает
твв дискеты: 360 К байт дли дисковода 360 К байт (Л=1) */
_АйгОх1Т; Л=0; Л=1;
geninterrupt(0xl3); /» вызов врерывавия 0x13 4/
/» Форхаировавве 4-й дорохки (JI - число секторов; Л -
яонер хисковоха; JB - воиер дорохки; J8 - покер стороны 4/
Л: JS; /« указатель ва сегиепт данных 4/
JX=(unsigned)Kas; /» мевеяке в сегиеите даииык »/
ЛЬ5; /» фупкцин форматирования »/
Л=9; /» число секторов 4/
Л=0; /« ноиер дисковода 4/
_СВ=4; /4 ноиер дорохки 4/
J8-0; /4 воиер норови ♦/
geninterrupt(0xl3); /» вызов прерывания 0x13 4/
/4 чтение данных вз 6-го сектора 4-й дорохки (_АВ=21 4/
JS=J8; Лг-(unsigned) str; _ДН-2; JB=0;
JB=4; Л4; Л=0;
Л:6; /4 ноиер сектора 4/
geninterrupt(0xl3); /» вызов прерывании 0x13 4/
/» вывод ка зкрая данных кз 6-го сектора 4-й стороны 4/
for (Ц0; ><512; Щ) printffix', str(1J);
puts('\nBaxKKre 512 раз лвбые ххавник');
/* с клавиатуры без зка на дисплей вводятся 512 символов 4/
for(i=0;i<512;iH) str[lj = getch(); _gS=JS;
/4 запись введенных даннык в заданный сектор диска >/
_BX-(unsignedJstr; /4 снедение дли блока ваияти 4/
_АВ=3; /« ноиер функции ни црерываяии 0x13 4/
JB-0; /« ноиер стороны диска »/
J8--4, /» ноиер дорохки 0 - В 4/
15 Скляров В. А.
433
_СЬ=6; /» комер сектора »/
Jb=l; /» чесло секторов »/
JM; /» еоиер liuoiou (0 — А: п т.п.) »/
geninterrupt(Ох 13); /> вызов прерыванвя 0x13 >/
for(i=0;i<512;iH) str[i}=0; /> обнуление массива str «/
/» чтение даввых пз 6-го сектора 4-й сторона (_АН-2) »/
JS=JS; JBX=:(un3igned)str; _АН=2; JD0--O;
_СН=4; _С1=6;_А1=1; Л=0;
geninterrupt(Ох 13); /* вызов прерывания 0x13 >/
/< вывод прочитанных данных яа экран дионея »/
for(i=0;i<512;in) printf('He',str(i)); )
Сначала производится форматирование 4-й дорожки
диска, установленного в дисковод А. Затем осуществляет-
ся чтение данных из 6-го сектора 4-й дорожки (из каждого
байта должны читаться коды f6). После этого необходимо
ввести любые 512 символов (при вводе они не будут
отображаться на экране), которые записываются в 6-й
сектор 4-й дорожки. И, наконец, записанные символы
выводятся с диска на экран дисплея.
При работе с приведенной программой надо иметь
в виду, что информация на 6-й дорожке диска (установ-
ленного в дисковод А) будет испорчена.
Обслуживание коммуникационных каналов на нижнем
уровне осуществляется через прерывание 20 (14хб) Оно
включает следующие функции:
инициализация (установка в начальное состояние)
коммуникационного канала (АН=0) —на входе: DX —
номер канала (0 или 1); AL— байт для инициализации,
который включает биты: 0, 1 — длина пересылаемого
слова (10—7 бит, 11—8 бит), 2 — число стоп-битов (0—
1 стоп-бит, 1—2 стоп-бита), 3, 4 — проверка (00 или 10 —
не производится, 01 — на нечетность, 11 — на четность),
5, 6, 7—скорость передачи— (000—110 с'1, 001 —
150 с'1, 010—300 с'1, 011—600 с , 100—1200 с'1, 101 —
2400 с'1, 110—4800 с'1, 1 11—9600 с'1);
посылка символа в выбранный коммуникационный ка-
нал (АН= 1) —на входе: DX — номер канала (0 или
1); AL— посылаемый символ; на выходе: если бит 7 АН
установлен в единицу, произошла ошибка; остальные би-
ты АН — состояние линии связи;
прием символа из выбранного коммуникационного ка-
нала (АН= 2) — на входе: DX — номер канала (0 или 1);
на выходе AL — принятый символ; если АН — не нуль,
произошла ошибка;
получение информации о состоянии коммуникацион-
ного канала (АН= 3) — на входе: DX — номер канала
(0 или 1); на выходе: АХ—информация о состоянии
434
канала (для значения в АН см. § 2.5, порты 3FD16 или
2FD16, в AL будет находиться статус модема).
Ниже приводится программа, иллюстрирующая основные правила
работы с прерыванием 20; с ее помощью настраивается коммуникацион-
ный канал COM2 и осуществляется пересылка данных на графопострои-
тель МР3100:
^include <dos.h>
>ain() /» работа с графопостроителем НР3100 »/
( unsigned char sir[}="И500,500.D1500,700\3';
int i;
It вщача Инзой в коииушацноннин капав COM2 »/
_АВ-1; JX=1; JI:
/> вчдача строка снчвоив в комкуннкацнонный кавав COM2 >/
geninterrupt(0x141;
for( 1=0;str[i}1-'\0';itI) ( _AH=1; JXrl; Jl= str(i);
geninterrupt(OiU); )
12.3.5. Краткая характеристика других прерываний BIOS
Векторы 29 (1 Dj6), 30 (lEie), 31 (1F16) указывают на
специальные таблицы: первая содержит информацию о па-
раметрах дисплея, вторая описывает параметры для нако-
пителей на гибких магнитных дисках. Работа с вектором
31 была описана в гл. 11.
Рассмотрим некоторые функции вектора 21 (15ie):
ожидание события (АН=8316) —на входе: AL= 0 —
установить интервал и запустить таймер (СХ, DX —
длина интервала в микросекундах, для которой старшая
часть — в СХ; ES:BX — адрес байта, в котором по истече-
нии интервала бит 7 будет установлен в единицу); AL =
= 1 — отменить ожидание события;
реакция на клавишу Sys-Req (AH = 85i6) — здесь ни-
чего не происходит. Эта функция вызывается нажатием
и отпусканием клавиши Sys-Req. На входе AL=0, если
клавиша Sys-Req должна быть нажата, и AL= 1, если кла-
виша Sys-Req должна быть отпущена.
Вектор 25 (191б) может использоваться для перезагруз-
ки ОС после каких-либо изменений списка оборудования
или переменных BIOS (предварительно в слово по адресу
0:0472 необходимо передать значение 1234ie) -
Вектор 28 (ICie) активизируется приблизительно 18,2
раза в секунду и может использоваться как прерывание
пользователя по таймеру.
435
12.4. ПРЕРЫВАНИЯ ОПЕРАЦИОННОЙ СИСТЕМЫ
12.4.1. Общие сведения
Верхний уровень обработки прерываний ОС образует
модуль IBMDOS.COM, с которым взаимодействует боль-
шинство прикладных программ. Его компонентами явля-
ются подпрограммы, обслуживающие работу файловой
системы и устройств ввода-вывода, организующие взаимо-
действие прикладных программ, выделение системных ре-
сурсов и т. п. Ниже приводится перечень основных пре-
рываний ОС:
завершение программы — 32(20). Это прерывание ис-
пользуется для возврата управления родительскому про-
цессу (обычно интерпретатору команд ОС — COMMAND.
СОМ);
обращение к функциям ОС— 33 (21);
адрес программы обработки завершения задачи —
34 (22). Адрес в этом векторе представляет собой точку
входа, в которую будет передано управление, когда теку-
щая программа завершится по прерываниям 32, 39 либо
функциям О, 4С16, 3116 прерывания 33;
адрес программы реакции на нажатие клавиши Ctrl —
Break— 35 (23). По адресу в этом векторе управление
передается, когда пользователь нажимает клавиши УПР—
СТОП (Ctrl—Break). Обычная системная проверка
Ctrl — Break вызывает немедленное снятие программы;
адрес программы реакции на фатальную ошибку —
36 (24). Этот вектор хранит адрес, по которому пере-
дается управление, когда драйвер устройства ОС обнару-
живает критическую ошибку (нормальный обработчик
ОС — это тот, который выдает сообщение: Abort, Retry,
Ignore?);
абсолютное чтение с заданных секторов д,иска —
37 (25);
абсолютная запись на заданные секторы диска —
38 (26);
завершение программы, оставляющее ее резидентом,—
39 (27);
мультиплексное прерывание — 47 (2F). Этот вектор
представляет средства управления процессами.
В последующем изложении основное внимание будет
уделено прерыванию 33, объединяющему множество
функций. Фактически эти функции позволяют выполнять
все перечисленные выше операции, но их использование
436
считается более предпочтительным, чем прерываний 32,
34, 35, 36, 37, 38, 39, 47.
12.4.2. Функции операционной системы
Ниже приведен перечень основных функций ОС:
завершение программы — 0 (0);
ввод символа с клавиатуры с эхом на дисплей — 1 (1);
вывод символа на экран дисплея — 2 (2);
ввод символа из коммуникационного канала — 3 (3);
вывод символа в коммуникационный канал — 4 (4);
вывод символа на принтер — 5 (5);
обмен символами с терминалом (клавиатура и дисп-
лей) — 6 (6);
ввод символа с клавиатуры без эха на дисплей без
проверки на Ctrl — Break— 7 (7);
ввод символа с клавиатуры без эха на дисплей с про-
веркой на Ctrl — Break — 8 (8);
вывод строки символов на экран — 9 (9);
ввод с клавиатуры с буферизацией — 10 (А);
проверка наличия ввода с клавиатуры — 11 (В);
очистка буфера ввода с клавиатуры— 12 (С);
сброс диска, сохранение буферов диска — 13 (D);
установка текущего диска — 14 (Е);
открытие файла с использованием блока управления
(FCB) - 15 (F);
закрытие файла с использованием FCB — 16 (10);
поиск первого имени файла, удовлетворяющего шаб-
лону,— 17 (11);
продолжение поиска имен файлов, начатого функцией
17,-18 (12);
удаление файлов с диска— 19 (13);
последовательное чтение из файла — 20 (14);
последовательная запись в файл—21 (15);
создание файла и его открытие для чтения / записи —
22 (16);
переименование файлов (с использование шабло-
нов) — 23 (17);
внутренняя операция ОС — 24 (18);
определение текущего диска — 25 (19);
установка адреса буфера передачи данных (Disk
Transfer Address — DTA) — 26 (1A);
получение информации о таблице размещения файлов
(File Allocation Table — FAT) для текущего диска —
27 (1В);
437
получение FAT для заданного устройства — 28 (1С);
внутренние операции ОС — 29—32 (1D — 20);
чтение с диска с прямым доступом — 33 (21);
запись на диск с прямым доступом — 34 (22);
выдача длины файла — 35 (23);
задание номера записи для прямого доступа — 36 (24);
установка вектора прерывания — 37 (25);
создание программного сегмента— 38 (26);
чтение блока с прямым доступом — 39 (27);
запись блока с прямым доступом — 40 (28);
преобразование имени файла во внутренние пара-
метры — 41 (29);
выдача текущей даты — 42 (2А); '
установка текущей даты — 43 (2В);
выдача текущего времени — 44 (2С);
установка текущего времени — 45 (2D);
установка/отмена верификации записи на диск —
46 (2Е);
выдача адреса буфера передачи данных (DTA) —
47 (2F);
выдача номера версии DOS — 48 (30);
завершение программы и сохранение ее резидентом —
49 (31);
дать информацию о диске— 50 (32);
установка или отмена проверки на Ctrl — Break —
51 (33);
внутренняя операция ОС — 52 ( 34);
выдача вектора прерывания— 53 (35);
выдача размера свободного пространства на диске —
54 (36);
внутренняя операция ОС — 55 (37);
выдача форматов даты, времени, чисел, денежных еди-
ниц, принятых в разных странах,- 56 (38);
создание подкаталога—57 (39);
удаление подкаталога—58 (ЗА);
установка текущего подкаталога — 59 (ЗВ);
создание файла (без использования FCB) — 60 (ЗС);
открытие файла (без использования FCB) —61 (3D);
закрытие файла (без использования FCB) — 62 (ЗЕ);
чтение из файла или ввод с устройства — 63 (3F);
запись в файл или вывод на устройство— 64 (40);
удаление файла из указанного каталога—65 (41);
установка позиции для последовательного доступа —
66 (42);
установка атрибутов файла — 67 (43);
438
управление устройством ввода-вывода (IOCTL) —
68 (44);
дублирование номера файла—69 (45);
соединение дублированных номеров файлов — 70 (46);
выдача текущего каталога — 71 (47);
выделение блока памяти из свободного пространства —
72 (48);
освобождение блока памяти — 73 (49);
изменение длины выделенного блока памяти — 74
(4А);
загрузка/выполнение программы— 75 (4В);
завершение программы с возвратом управления —
76 (4С);
выдача кода завершения программы — 77 (4D);
поиск первого файла каталога по шаблону — 78 (4Е);
продолжение поиска файлов каталога по шаблону —
79 (4F);
внутренние операции ОС — 80—83 (50—53);
выдача признака режима верификации— 84 (54);
внутренняя операция ОС — 85 (55);
переименование файла—86 (56);
выдача даты и времени модификации файла —
87 (57);
получение информации о кодах ошибок— 89 (59);
создание временного файла — 90 (5А);
создание нового файла — 91 (5В);
блокирование/разблокирование доступа к файлу —
92 (5С);
сетевые функции — 93 (5Е);
переназначение устройств в сети — 94 (5F);
получение сегментного адреса префикса программного
сегмента (Program Segment Prefix — PSP) текущей
выполняемой программы — 98 (62).
12.4.3. Ввод-вывод символов, чисел и строк
Рассмотрим функции ОС с номерами 1—12. Они пред-
назначены для ввода-вывода символов, чисел и строк.
Соответствующий номер должен быть занесен в регистр
АН перед вызовом прерывания 33. Ниже дается краткая
характеристика этих функций:
АН= 1 — на выходе: AL— символ, принятый со стан-
дартного входа (с клавиатуры);
АН=2 — на входе: DL — символ, передаваемый на
стандартный выход (на дисплей);
439
АН= 3 — на выходе: AL — символ, принятый со стан-
дартного коммуникационного канала (при запуске ОС
канал AUX инициализируется на скорость 2400 с-1 без
проверки на четность, с одним стоп-битом и восьмибито-
выми словами);
АН=4—на входе: DL — символ, передаваемый
в стандартный коммуникационный канал;
АН= 5 — на входе: DL — символ, подлежащий выво-
ду на принтер;
АН=6 — если на входе в регистр DL записан код
ff 16, символ вводится со стандартного входа и помещается
в регистр AL; если на входе в регистре DL записан другой
код, соответствующий ему символ выводится на экран;
АН= 7 — на выходе: AL — символ, принятый со стан-
дартного входа;
АН= 8 — на выходе: AL — символ, принятый со
стандартного входа;
АН= 9 — на входе: DS: DX — сегментный адрес и сме-
щение для выводимой строки, которая должна заканчи-
ваться символом $;
АН= 10— на входе: DS:DX — сегментный адрес
и смещение входного буфера;
АН=11—на выходе: AL=0, если буфер пуст;
AL=ffie, если буфер не пуст;
АН= 12 — на входе: AL — номер функции для ввода
символа (см. функции АН= 1, АН= 6, АН= 7, АН=9,
АН= 10).
Приведем текст программы, в которой показывается использование
большинства из рассмотренных функций:
^include <dos.h>
Hinclnde <conio.h>
»ain()
( unsigned char si», з1г[]='Кафедра 3 В Г;
clrscrl); /» очистка экрана »/
/> ввод cuHsoia с клавиатуры с эко» па дисплей Ч
_ЛВ-1; geninterrupt(33);
printf(“\nsi» -
/> вывод CHHsoia па экрав jncniei >/
JB=2; JL:sin; geninterrupt(33);
/< вывод cnnsoia па орпптер »/
_AHtS; Jlrsin; geninterruptl33);
/> ввод cinsoia с каавнатур» без эка па дяспкей Ч
_АН-8; geninterruptl33); si»:_Ah;
printf(”\nsiB - Uc\n',sie);
/> вывод па экрав строк», закаичивавценся с»»воао» $ </
str[strlen(str)]=$';
_АН=9; Jx4p_oh(str); geninterruptl33);
/> проверка состовпп! входного буфера Ч
440
JB-11; geninterrupt(33J; sh-_AL;
pnts('\пбуфер ae syct");
else puts('\n6y$ep syct');
/> 000* casaoja аз буфера tiaimipi </
JB-6; JIisdsFF; geninterrnpt(33); si®=_AL;
/> 0Ы0ОД введенного chkboib ве экран >/
printf('\nsi> -
JB=6; Jb=sii; geninternpt(33); )
Для того чтобы буфер клавиатуры не был пуст, необходимо в про-
цессе компиляции программы нажать на 1 — 2 с любую клавишу.
12.4.4. Работа с файлами
Перечислим функции ОС, предназначенные для работы
с файлами:
АН= 13— все буферы файлов сбрасываются на диск;
АН= 14 — на входе: DL — номер диска, который дол-
жен стать текущим (0 — А, 1 — В и т. п.); на выходе: AL—
число логических дисковых устройств;
АН= 15— на входе: DS:DX— указатель на неоткры-
тый блок управления файлом (FCB); на выходе: если
указанное в FCB имя не найдено в каталоге, в AL возвра-
щается ff16; если же оно найдено, в AL возвращается
нуль и заполняется FCB;
АН= 16—на входе: DS:DX — указывает на откры-
тый блок управления файлом, указанный файл ищется в
каталоге; на выходе: если файл не найден, в AL возвра-
щается ff16; если же он найден, в AL возвращается нуль
и производится модификация каталога;
АН= 17 — на входе: DS:DX — указывает на FCB; на
выходе: значение в AL (аналогично предыдущим слу-
чаям);
АН= 18 — входные и выходные данные совпадают с
предыдущей функцией;
АН= 19 — на входе: DS:DX — указывает на неоткры-
тый FCB, все соответствующие элементы каталога и файлы
уничтожаются; на выходе: если удаляемых элементов нет,'
AL = ff16; в противном случае AL=0;
АН=20 — на входе: DS:DX — указывает на открытый
FCB; запись, указываемая номером текущего блока и но-
мером текущей записи, пересылается в буфер; на выходе:
AL=0, если чтение было успешным; AL= 1, если достигнут
конец файла и данные не были считаны; AL= 2, если
чтения не было; AL= 3, если считана усеченная за-
пись;
АН=21—на входе: DS:DX — указывает на откры-
тый FCB, запись из буфера пересылается на диск: на выхо-
441
де: AL = 0, если запись была успешной; AL= 1 илиАЬ=2,
если данные не записаны;
АН=22 — на входе; DS:DX — указывает на неоткры-
тый FCB; на выходе: AL=0, если файл создан без ошибок;
AL= 11!6, если файл не может быть создан;
АН=23 — на входе:Н5:НХ— указывает на FCB; вы-
ход подобен предыдущей функции;
АН=25—на выходе: AL—номер текущего диска
(О — А, 1 — В ит. п.);
АН=26— на входе;Н5:НХ— указатель на область
памяти, которая становится текущим буфером (DTA);
АН=27 — на выходе;DX — число кластеров на диске;
AL — число секторов в кластере; СХ — длина физического
сектора; DS;BX — адрес байта ТРФ с форматом диска;
АН=28 — аналогична функции АН=27, но на входе
DL содержит номер дисковода (0 — текущий диск, 1 — А и
т. п.);
АН=33 — на входе:DS:DX — указывает на открытый
FCB, соответствующая запись пересылается в буфер; на
выходе: AL=0, если чтение было успешным; AL= 1 или
AL=2, если чтения не было; AL=3, если считана усечен-
ная запись:
АН=34 — аналогична функции АН=33;
АН=35 — на входе: DS:DX — указывает на неоткры-
тый FCB; на выходе: AL= 0, если файл найден; AL= FF16,
если файл не найден;
АН=36 — на входе:В5:ВХ— указывает на открытый
FCB; в поле номера записи для прямого доступа заносится
значение, соответствующее номеру текущего блока и номе-
ру текущей записи;
АН=39 — на BxoAe:DS:DX — указывает на открытый
FCB; СХ — число считываемых записей; на выходе:
СХ — число фактически считанных записей; AL — анало-
гична функции АН =33; »5
АН=40 — аналогична функции АН= 39, но происхо-
дит не чтение, а запись;
АН=41 — на входе: DS:SI — указывает на командную
строку; ES:DI — указывает на область памяти, где форми-
руется неоткрытый FCB; AL — код выполняемых действий
(можно задать AL=0);
АН=50 — на входе: DL — номер диска (0 — текущий,
1 — А и т. п.); на выходе: AL=0, если в DL задан кор-
ректный диск; AL = FF|6, если диск задан неверно;
DS:BX — адрес блока информации диска для запро-
шенного устройства;
442
АН=54 — на входе: DL — номер дисковода (0 — те-
кущий, 1—А и т. п.); на выходе: AX=ffff1e, если задан
недопустимый номер; в противном случае ВХ — число
свободных кластеров на диске; DX — общее число класте-
ров; СХ — число байтов в секторе; АХ — число секторов
в кластере;
АН = 60— на входе: DS:DX—указывает на строку,
содержащую имя дисковода, составное имя каталога, имя
файла и заключительный нуль; СХ— атрибуты файла; на
выходе: АХ — код ошибки, если CF установлен, или номер
открытого файла, если ошибки нет;
АН=61 — на входе: DS:DX в том же формате, что и
для функции АН=60; AL — код доступа (0 — для чтения,
1 — для записи, 2 —для чтения и записи); выход тот же,
что и для функции АН=60;
АН=62—на входе: ВХ—номер файла; на выходе:
АХ — код ошибки, если CF установлен;
АН=63 — на входе: ВХ — номер файла; СХ — число
байтов для чтения; DS:DX — адрес буфера для чтения
данных; на выходе: АХ — число фактически прочитанных
байтов или код ошибки, если CF установлен; чтение
осуществляется, начиная с текущей позиции;
АН=64 — подобна функции АН=63, но используется
для записи в файл или устройство;
АН=65 — на входе: DS:DX—адрес строки с мар-
шрутом к файлу; на выходе: АХ — код ошибки, если CF
установлен;
АН=66 — текущая позиция определяет номер байта в
файле, с которым будет выполняться следующая опера-
ция обмена. На входе: ВХ — номер файла; AL — код
операции; CX:DX — номер необходимой позиции (стар-
шая часть в СХ); на выходе: DX:AX — номер новой те-
кущей позиции (старшая часть в DX). В AL можно запи-
сать следующие коды операций: 0 — установка позиции
относительно начала файла, 1 — относительно текущей
позиции, 2 — относительно конца файла. Если CF установ-
лен, то в АХ — код ошибки;
АН=67 — на входе: если AL=0, атрибуты файла
возвращаются в СХ; если AL=1, файлу назначаются
атрибуты, заданные в СХ. Если CF установлен, то в АХ —
код ошибки;
АН=69—на входе: ВХ — номер файла; на выходе:
АХ — новый номер, указывающий на тот же файл. Если
CF установлен, то .в АХ— код ошибки;
АН=70 — на входе: ВХ — номер файла. После выпол-
443
нения функции СХ указывает на тот же файл, что и ВХ;
АН=90 — на входе: DSrDX — указывает на строку с
именем диска и маршрутом к файлу; СХ — атрибут файла;
на выходе: АХ—код ошибки (если CF установлен);
DS:DX — указывает на полную спецификацию нового
файла;
АН—91 — на входе: DS:DX — указывает на строку со
спецификацией файла; СХ — атрибут файла; на выходе:
АХ — код ошибки (если CF установлен).
Ниже приводится текст программы, в которой показывается ис-
пользование некоторых из рассмотренных функций:
Miclude <dos.h>
finclude <stdio-h>
nin()
( ist i,clus,sect,byte;
unsigned dds;
/» набор диска a: »/
_AH=14; JW; geBinterrupt(331; l=Jl;
priBtf("\no6gee число дисков: ld\B",i);
/» определение текшего дней ( будет 0 - а: ) »/
JB:25; geBiBterrupt(33J; 1-_AL;
рпиНСтенуднй диск: Jd\B*,i);
/» получение информации о таблице разнедевкя файдов »/
dds-JS; /» сохранение адреса сегиента давних »/
_АВ-27; geBieterruptl33);
chs:JX; sect-Л; byte:.!!;
JS=dds; /» восстановление адреса сегиента данных »/
printf("\п\ТДйСК А:\поблее число кластеров: И;\в«Г
"ело секторов в кластере: Sd;\n4Htao байтов"
в секторе: %d.\n\n“,clus,sect,byte);
Il ношение информации о таблице разведений файдов л/
dds:JS; /» сохранение адреса сегиента данных »/
_А0:2В; Jb:3; /» диск с: »/ geninterrupt(33);
t.ius:_DX; sect:_AL; byte:.!!;
JS:dds; /» восстановление адреса сегиента данных »/
Printff'WCK СЦпоблее число кластеров: И;\мкдо"
' секторов в кластере: МДпчнсло байтов в сен"
“ope: W.\n",cl:ls,sect,byte);
/» получение информации о свободном пространстве на диске »/
_ДЯ=54; Л=0; geninterrupt(33);
clus:JX; printf( Дпсвободнм кластеров: И.\в", clus); •:
)
12.4.5. Системные операции и работа с каталогами
Перечислим функции ОС для выполнения системных
операций и работы с каталогами:
АН=37 — на входе:AL— номер прерывания;П5:ПХ—
устанавливаемый вектор прерывания;
АН=38—на входе:БХ—сегментный адрес, где со-
здается новый программный сегмент, при этом текущий
префикс программного сегмента (256 байт) копируется
444
в новый программный сегмент; в новом префиксе изме-
няется размер доступной памяти;
АН=42 — на выходе: СХ — год после 1980-го; DH —
номер месяца (1 — январь и т. д.); DL — день месяца;
AL—день недели (0 — воскресенье, 1 — понедельник и
т. п.);
АН=43 — на входе: CX:DX — дата в том же формате,
что и для функции АН=42. Если дата задана правильно,
то она устанавливается и в AL возвращается нуль; в
противном случае дата не меняется и в AL возвращается
f f । б’,
АН = 44 — на выходе: СН — часы (от 0 до 23); CL —
минуты (от 0 до 59); DH — секунды (от 0 до 59); DL —
сотые доли секунды (от 0 до 99);
АН=45 — на входе: CX:DX — содержит время в том
же формате, что и для функции АН=44; на выходе тот же
результат, что и для функции АН =43;
АН=46 — на входе: AL= 1 — устанавливается режим
записи с контрольным считыванием; AL=O—устанав-
ливается режим без контрольного считывания;
АН= 47 — на выходе: ES:BX — адрес текущего буфе-
ра DTA;
АН = 48 — на выходе: AL — старшая часть версии ОС
(до точки); АН — младшая часть версии ОС (после
точки);
АН=49 — на входе:АЬ— код возврата; DX — размер
памяти в параграфах. Код возврата доступен родитель-
скому процессу через функцию 4D, а также команде
ERRORLEVEL в командных файлах;
АН=51 — на входе: если AL=0, опрашивается состо-
яние Ctrl—Break (УПР—СТОП); если AL=1, осуще-
ствляется установка реакции на Ctrl — Break; при уста-
новке DL = O отменяет действия по Ctrl — Break, DL=-1
назначает прерывание процесса по Ctrl — Break; на выхо-
де: DL= 0, если не были нажаты клавиши Ctrl — Break;
АН= 53 — на входе: AL — номер прерывания; на вы-
ходе: ES:BX — вектор прерывания (адрес входа в про-
грамму обработки прерывания);
АН=57 — на входе: DS:DX — указатель на строку,
содержащую имя дисковода и составное имя ката-
лога, на выходе: АХ — код ошибки, если CF установ-
лен;
АН=58— на входе: DS:DX в том же формате, что и
для функции АН=57 (выход тоже аналогичен);
445
АН=59 — на входе: DS:DX в том же формате, что и
для функции АН=57 (выход аналогичен);
АН=68 — на входе: AL—код подфункции [18]; на
выходе: АХ — код ошибки, если CF установлен;
АН=71 — на входе: DL — номер дисковода (0— те-
кущий диск, 1—А и т. д.); DS:SI — указатель на область
памяти длиной 64 байта (в нее помещается полное
составное имя текущего каталога); строка начинается с
первой буквы подкаталога в корневом каталоге и закан-
чивается нулевым байтом; на выходе: АХ — код ошибки,
если CF установлен;
АН=72 — на входе: ВХ — длина необходимого блока
памяти в параграфах, на выходе: АХ:0 — указатель на
выделенный блок памяти (четыре шестнадцатеричные
цифры в АХ и один шестнадцатеричный нуль). Если выде-
лить блок заданной длины невозможно, в ВХ возвращается
размер максимального свободного блока в параграфах
(если CF установлен, в АХ — код ошибки);
АН=73—на входе: ES:0—указатель на начало
освобождаемого блока памяти, выделенного функцией
АН=72;
АН=74 — на входе: ES:0 — указатель на начало осво-
бождаемого блока памяти, выделенного функцией
АН=72; ВХ — новая длина блока памяти в параграфах.
Если увеличить блок до заданной длины невозможно, в
ВХ возвращается максимальный возможный размер в па-
раграфах (если CF установлен, в АХ — код ошибки);
АН=75—на входе:В8:ВХ — указатель на строку,
содержащую имя дисковода, составное имя каталога и
имя файла с загружаемой задачей; ES:BX — указатель
на блок параметров для загрузчика; AL— код операции
(AL=0—загрузить и выполнить программу, AL=3 —
загрузить, не создавать префикс программного сегмента
и не выполнять; это необходимо для программного
оверлея). Блок параметров включает: сегментный адрес
передаваемой среды; указатель на командную строку;
указатель на FCB, помещаемый в префикс программного
сегмента со смещением 5С\б; указатель на FCB, поме-
щаемый в префикс программного сегмента со смещением
6С]б. В случае операции AL=3 блок параметров включает:
сегментный адрес области памяти, куда загружается зада-
ча; адрес, на который настраивается загружаемая задача
(если CF установлен, то в АХ— код ошибки);
АН=76 — на входе: AL— код возврата, при этом за-
канчивается выполнение текущего процесса и передается
446
управление родительской задаче. Код возврата может
анализироваться командами IF и ERRORLEVEL в команд-
ных файлах. Все файлы, открытые заканчивающейся
задачей, закрываются;
АН=77 — на выходе:AL — код возврата для послед-
ней заканчивающейся задачи (функции АН=49 и
АН=76). Если АН=0,— нормальное завершение; если
АН= 1,— по Ctrl—Break; если АН=2,— фатальная ошиб-
ка; если АН=3 — завершение по функции АН=49;
АН=78—на входе: DS:DX — указатель на строку,
содержащую имя дисковода, составное имя каталога, имя
файла и заключительный нуль; СХ — атрибуты, которые
должны иметь искомые файлы; на выходе: АХ — код
ошибки, если CF установлен; в противном случае DTA
будет заполнена данными;
АН=79— выполняется после функции АН=78;
АН= 84 — на выходе: AL= 0, если не установлен ре-
жим верификации (контрольного считывания); AL= 1,
если этот режим установлен;
АН=87 — на входе: AL=0 или AL= 1; ВХ — номер
файла. Если AL=0, в DX и СХ возвращаются дата и
время создания или модификации файла из каталога;
если AL=1, в каталог заносятся дата и время создания
или модификации файла из регистров DX и СХ;
АН=89 — на входе: ВХ=0; на выходе: АН — код
ошибки (0, если ошибка не обнаружена); ВН — класс
ошибки; BL — предлагаемые действия; СН — место, где
обнаружена ошибка;
АН=98 — на выходе: ВХ — сегментный адрес префик-
са программного сегмента текущей выполняемой про-
граммы.
Ниже приводится текст программы, в которой показывается
использование некоторых из рассмотренных функций:
^include <stdio h>
Jinclade <doa.h>
main ()
( int dn,yd,h,«in,s,hs.non;
char skfP'WAL', kat(65], f;
/< подучеме информации о тещей дате »/
.АВЩ; geninterrupt(33);
У=_СК; JB; d=JL;
pnntf('Лпдень недедн- И;\пгоД: ИДпиесиц: ?d;\n"
'чнсдо: M.\n\n',dn.y,s,d);
/» подученне информации о тещев времеив «/
_JB-44; geninterrapt(33);
k_CB; «in-_CL; s^.DB; hs-JL;
printff“часы: ИДпкннути: НЦпсекундв: Xd;\ncoTBe "
додп седундв: Xd,\n\n",h,»in, з,hз);
447
/* создавав подкаталога ША[> »/
_АН=5Т; _№FP_OFF(sk);
geninterrupt(33);
/к выдача текнего подкаталога к/
J0--T1; JL--0; _SLF?_OFF(kat);
geninterrupt(33);
printf("ТекпЕй подкаталог- Rs\n',kat);
/* установка текущего подкаталога RATAL к/
JB--59; JX:FP_0FF(3k);
geninterrnpt(33);
/* выдача текущего подкаталога к/
_АВ=Т1; JL--0; _SI-FPJ)FF(kat) ;
geninterrupt(33);
printfCTewA подкаталог: »з\п‘ ,kat);
/» создание файла fil.f в мташе RATAL к/
_АВ-60; JX--FP_OFF(f); _СХ=О;
geninterrupt!33);
/« онрвне файла fil.f ни записи »/
JB--61; JX:FP_OFF(f); JL--1;
gen interrupt! 33); no>tJX;
printf('Ro»ep Файла: Rd\n',not);
/» заись s файл fil.f пне байт слова RATAL к/
_АВ:61; JR:no>; _CX:5; JtFP_OFF(зк);
gen interrupt!33);
/к закрытие файла fil.f к/
_АВ=62; _№по>; genlnterrupt(33); )
Сначала выдается информация о текущих дате и времени. Их
можно изменить с помощью команд ОС date и time. Затем в текущем
каталоге создается подкаталог KATAL. Далее определяется имя теку-
щего каталога, осуществляется переход к текущему каталогу KATAL
и выдается его имя. В заключение в каталоге KATAL создается
файл с именем fil.f. Он открывается на запись, и в пего записываются
5 байт слова KATAL. В конце приведенной программы файл fil.f
закрывается.
ПРИЛОЖЕНИЕ
В приложении рассматриваются коды, используемые в ПЭВМ, и
описываются различные команды управления принтером. К управляю-
щим относятся коды с десятичными номерами 0—31, 127. В табл.
П. 1 указывается назначение каждого из них.
Таблица П.1
Код Символ Клавиши Назначение
деся- тичный шест- надца- терич- ный
1 2 3 4 5
0 00 NUL УПР — @ Машинный нуль (null) 1 01 SOH УПР—А Начало заголовка (start of heading) 2 02 STX УПР—В Начало текста (start of text) 3 03 ЕТХ УПР—С Конец текста (end of text) 4 04 EOT УПР—D Конец передачи (end of trans- mission) 5 05 ENQ УПР — E Справка (enquiry) 6 06 ASK УПР—F Подтверждение (acknowledge) 7 07 BEL УПР—G Звонок (bell) 8 08 B.S УПР—H Шаг назад (back space) 9 09 НТ . УПР — I Горизонтальная табуляция (tab horizontallv) 10 OA LF УПР—J Перевод строки (line feed) 11 OB VT УПР—К Вертикальная табуляция (tab verticaly) 12 ОС FF УПР—L Подача формата (form feed) 13 OD CR УПР—M Возврат каретки (carriage re- turn) 14 OE SO УПР—N Внешнее перемещение (shift out) 15 ОГ SI УПР—О Внутреннее перемещение (shifft in) 16 10 DLE УПР—P ESC-последовательность (data line escape) 17 11 DC1 УПР—Q Управление 1 (device control 1) 18 12 DC2 УПР—R Управление 2 (device control 2) 19 13 DC3 УПР—S Управление 3 (device control 3) 20 14 DC4 УПР—T Управление 4 (device control 4)
449
Окончание табл. П. 1
1 2 3 4 5
21 15 NAK УПР — U Отрицательное подтверждение (negative acknowledge) 22 16 SYN УПР—V Синхронизация (synchronous idle) 23 17 ЕТВ УПР — W Конец передаваемого блока (end of transmitted block) 24 18 CAN УПР — X Отмена линии (cancel line) 25 19 EM УПР—Y Переход через середину (end of medium) 26 ,1A SUB УПР—Z Конец текстового файла (sub- stitute) 27 IB ESC УПР—[ Символ ESC (escape) 28 1C ES УПР - \ ' Разделитель файла (file sepa- rator) 29 ID GS УПР—j Разделитель групп (group sepa- rator) 30 IE RS УПР— Разделитель записей (record separator) 31 IF US УПР Разделитель единиц (unit se- parator) 127 7F DEL ДОП — 8 Забой (удаление символа) Табл. П.2 содержит ASCII-коды символов. Код 32 соответствует пробелу. Таблица П.2
К од 6 со 5 , Коч Символ j Код Символ Код Символ Код Сим- вол
’Е X ГС 0J Ч 1И0СТ- надца- тсрич- иый [десятичный j иК'СТ- мадца- терич- н ый ГС 1J шее т- надца терич- пый 3 S ГС п шест - падца- 1 грип- пы й ? S шест* надца- терич- иый
32 20 44 2С 33 21 । 45 2D - 34 22 46 2Е . 35 23 # 47 2Е / 36 24 S 48 30 0 37 25 % 49 31 1 38 26 & 50 32 2 39 27 ' 51 33 3 40 28 ( 52 34 4 41 29 ) 53 35 5 42 2А *' 54 .36 6 43 2 В Д 55 37 7 92 5С \ 99 63 с 93 5D | 100 64 d 94 5Е л 101 65 е 95 5F — 102 66 f 96 60 ' 103 67 g 97 61 а 104 68 h 98 62 b 105 69 i 56 38 8 68 44 D 80 50 Р 57 39 9 69 45 Е 81 51 Q 58 ЗА : 70 46 F 82 52 R 59 ЗВ ; 71 47 G 83 53 S 60 ЗС < 72 48 Н 84 <54 Т 61 3D = 73 49 1 85 55 U 62 ЗЕ > 74 4А J 86 56 V 63 3F ? 75 4В К 87 57 W 64 40 @ 76 4С L 88 58 X 65 41 А 77 4D М 89 59 Y 66 42 В 78 4Е N 90 5А Z 67 43 С 79 4F О 91 5В [ 106 6А j 113 71 q 120 78 х 107 6В к 114 72 г 121 79 у 108 6С 1 115 73 s 122 7А z 109 6D m 116 74 t 123 7В { НО 6Е n 117 75 и 124 7С | 111 6F о 118 76 v 125 7D ' 112 70 р 119 77 w 126 7Е ~
450
Табл. П.2 содержит ASCll-коды символов. Код 32 соответствует
пробелу.
Табл. П.З содержит скэн-коды клавиш клавиатуры. В ПЭВМ ЕС
1840, ЕС 1841 на клавиатуре нанесены сокращения русскими буквами, а
для машин, выпущенных за рубежом, используются английские слова.
Ниже дается их соответствие: bksp — ; Tab — Shift — L — слева;
R—справа; Prt-Sc—ПЕЧ; Alt — ДОП; spacebar—пробел (—);
Caps-Lock — ФПБ; Num-Lock— ЦИФ; Scroll-Lock — ФСД; Ноте —
V Pg-Up —fi; End—КОН; Pg-Dn — Ins — ВСТ; Del — УДЛ;
Ctrl — УПР; Enter — ВВОД.
Табл. П. 4 содержит некоторые расширенные ASCll-коды. Для
клавиш УПР — £^,УПР— А—УПР—Z и некоторых других они соответ-
ствуют кодам, представленным в табл. П. 1. Это же относится и к кла-
вишам Р1(Ф1) — Р10(Ф10), а также таким, как КОН, ВСТ, УДЛ, f,
и др. Комбинациям клавиш Shift—Fl,..., Shift—F10 соответствуют
десятичные коды от 84 до 93, комбинациям УПР — F1,..., УПР — F10 —
десятичные коды от 94 до ЮЗ и, наконец, комбинациям ДОП— F1,...,
ДОП—F10 — десятичные коды от 104 до 113. После горизонтальной
черты в табл. П.4 записаны дополнительные коды расширенной
клавиатуры.
Таблица П.З
Скэн- код Кла- виша Скэн- код Кла- виша Скэн- код Кла- виша Скэн- код Кла- виша Скэн- код Кла- виша Скэн- код Кла- виша
1 ESC 16 Qii 31 Sbl 46 сс 61 F3 76 5
2 1! 17 WU 32 DB 47 VM 62 F4 77 ->6
3 18 ЕУ 33 FA 48 ВИ 63 F5 78 4“
4 3# 19 RK 34 Gn 49 NT 64 F6 79 КОН
5 48 20 ТЕ 35 HP 50 Mb 65 F7 80 ;2
6 5% 21 YH 36 JO 51 ,<B 66 F8 81 3
7 6Л 22 иг 37 КЛ 52 ,> Ю 67 F9 82 ВСТ
8 7 & 23 1Ш 38 1-Д 53 /? 68 F10 83 УДЛ
9 8* 24 ощ 39 ~ж 54 (R) 69 ЦИФ 84
10 9( 25 РЗ 40 л Э 55 ПЕЧ 70 ФСД 85
11 0) 26 {(X 41 56 ДОП 71 \ 7 86
12 27 )]Ъ 42 (1) 57 72 f8 87 F11
13 + = 28 ввод 43 \( 58 ФПБ 73 9 88 F12
14 bcsp 29 УПР 44 ZJI 59 Fl 74 —
15 Tab 30 АФ 45 ХЧ 60 F2 75 -<-4
Десятич- ный код Клавиши Десятич- ный код Клав»ши
30 ДОП—А 25 ДОП—Р
48 ДОП—В 16 ДОП—Q
46 ДОП —С 19 ДОП—R
32 ДОП—D 31 ДОП—S
18 ДОП—Е 20 ДОП—т
33 ДОП—F 22 доп—и
34 ДОП —С 47 ДОП—V
35 доп-н 17 ДОП—W
23 ДОП-1 45 ДОП—X
36 ДОП—J 21 ДОП—Y
37 ДОП-К 44 ДОП—Z
38 ДОП — L 129 ДОП—о
50 доп—м 120 ДОП-1
49 ДОП —N 121 ДОП—2
24 ДОП—О 122 ДОП—3
Таблица П.4
Десятич чый код Клавиши Десятич- ный код Клавиши Десятич- ный код Клавиши
123 ДОП—4 114 УПР—ПЕЧ 43 ДОП-\
124 ДОП—5 51 ДОП—,
125 ДОП—6 133 F11 52 ДОП-.
126 ДОП—7 134 F12 162 доп —вст
127 ДОП—8 135 Shift—F11 28 доп —ввод
128 ДОП—9 136 Shift—F12 1 ДОП —ESC
130 ДОП— 137 УПР—Fl 1 165 ДОП — Tab
131 ДОП- = 138 УПР—F12 148 УПР — Tab
115 УПР—*- 139 ДОП—Fl 1 152 ДОП — f
116 УПР > 140 ДОП—F12 160 Д О11 — j,
15 SH—Tab 26 доп-[ 155 ДОП —
117 УПР —КОН 27 ДОП-] 157 ДОП >
119 УПР— 39 ДОП—; 163 ДОП—УД Л
118 УПР—PD 40 ДОП-' 159 доп —кон
132 УПР — PU 41 ДОП-’ 151 доп — \
Комбинации клавиш Ctrl—Break (УПР—СТОП) соответствует рас-
ширенный ASCII-код 0, комбинации ДОП — пробел и ДОП — Pg-Up —
расширенные коды 14 и 153,
В табл. П. 5 приведены команды для управления принтером
типа EPSON FX-800/1000.
ТаблицаП.5
ASCII-код Код символов Назначение команды
деся- тичный шест- надца- терич- ный
1 2 3 4
ESC @ 64 40 Инициализация принтера
DC1 17 11 Перевод принтера в режим готовности
DC3 19 13 Перевод принтера в автономный режим
ESC s 115 73 Включение/выключение режима по поло- винчатой скорости
ESC 60 3C Выбор режима однонаправленной печати (только для одной строки)
ESC u 85 55 Включение/выключение режима однона- правленной печати
ESC 8 56 38 Отключение датчика конца бумаги
ESC 9 57 39 Включение датчика конца бумаги
ESC EM 25 19 Управление устройством для подачи листо- вой бумаги
ESC 61 3D Установка в нуль старшего бита всех поступающих данных
ESC 62 3E Установка в единицу старшего бита всех поступающих данных
ESC 35 23 Отмена установки старшего бита
BEL 7 7 Подача звукового сигнала
CR 13 D Возврат каретки
CAN 24 18 Отмена строки
DEL 127 7F Забой знака
FF 12 C Перевод формата
ESC C 67 43 Установка длины страницы в строках
ESC CO 67 43 Установка длины страницы в дюймах
ESC N 78 4E Установка пропуска линии перфорации
ESC 0 79 4F Отмена пропуска линии перфорации
LF 10 A Перевод строки
ESC 0 48 30 Выбор 1 /8-дюймового интервала между строками
ESC 1 49 31 Выбор 7/72-дюймового интервала между строками
ESC 2 50 32 Выбор 1/6-дюймового интервала между строками
ESC 3 51 33 Выбор n/216-дюймового интервала между строками
ESC A 65 41 Выбор п/72-дюймового интервала между
строками
453
Продолжение табл. П.5
1 2 3 4
ESC J , 74 4A Перевод строки на n/216 дюйма
VT 11 В Вертикальная табуляция
ESC В 66 42 Установка вертикальной табуляции
ESC b 98 62 Установка вертикальной табуляции в ка-
налах
ESC / 47 2F Выбор канала вертикальной табуляции
ESC 1 108 6C Установка левого поля
ESC Q 81 51 Установка правого поля
BS 8 8 Возврат на шаг
ESC 8 36 24 Установка абсолютного положения начала
печати
ESC \ 92 5C Установка относительного положения на-
чала печати
HT 9 9 Горизонтальная табуляция
ESC D 68 44 Установка горизонтальной табуляции
ESC x 120 78 Выбор качественного или черновикового
шрифта
ESC к 170 6B Выбор типа качественного шрифта
ESC! 33 21 Выбор комбинации шрифтов
ESC P 80 50 Выбор шрифта «пайка»
ESC M 77 4D Выбор шрифта «элит»
ESC p 112 70 Включение/выключение пропорционально-
го режима
SI 15 F Установка уплотненного шрифта
ESC SI 15 F Установка уплотненного шрифта
DC2 18 12 Отмена уплотненного шрифта
SO 14 E Установка удвоенной ширины знаков (для
одной строки)
ESC SO 14 E Установка удвоенной ширины знаков (для
одной строки)
DC4 20 14 Отмена двойной ширины знаков (для од-
ной строки)
ESC W 87 57 Включение/выключение режима двойной
ширины знаков
ESC w 1 19 77 Включение/выключение режима удвоенной
высоты знаков
ESC E 69 45 Выбор режима выделенного шрифта
ESC F 70 46 Отмена выделенного шрифта
ESC G 71 47 Установка двухударного режима
ESC H 72 48 Отмена двухударного режима
ESC SO 83 53 Установка режима верхнего индекса
ESC SI 83 53 Установка режима нижнего индекса
ESC I 84 54 Отмена режима верхнего/нижнего индекса
ESC- 45 2D Включение/отключение режима подчерки-
вания
ESC SP 32 20 Выбор межзнакового промежутка
ESC t 116 74 Выбор таблицы знаков
ESC 4 52 34 Установка режима курсива
ESC 5 53 35 Отмена режима курсива
ESC R 82 52 Набор международных знаков
454
Окончание табл. П.5
2 3
ESC & 38 26 Установка знаков, определяемых пользо-
вателем
ESC 58 ЗА Копирование ПЗУ в ОЗУ
ESC /0 37 25 Выбор набора определяемых пользовате- лем знаков
ESC К 75 4B Установка графического режима с одинар- ной плотностью
ESC L 76 4C Установка графического режима с двой ной плотностью
ESC Y 8S 59 Установка графического режима с высоко- скоростной двойной плотностью
ESC Z 90 5A Установка графического режима с учет- веренной плотностью
ESC 94 5E Выбор девятиигольной графики
ESC * 42 2A Выбор графического режима
ЛИТЕРАТУРА
1. Берри Р., Микинз Б. Язык СИ: Введение для программистов.—
М.: Финансы и статистика, 1988.— 75 с.
2. Болски М. И. Язык программирования СИ.— М.: Радио и
связь, 1988.— 96 с.
3. Брэдли Д. Программирование на языке ассемблера для персо-
нальной ЭВМ фирмы IBM.— М.: Радио и связь, 1988.— 448 с.
4. Брябрин В. М. Программное обеспечение персональных ЭВМ.—
М.: Наука, 1988.— 272 с.
5. Керниган Б., Ритчи Д. Язык программирования СИ.— М.:
Финансы и статистика, 1985.— 280 с.
6. МикроЭВМ (персонально-профессиональные ЭВМ) /Г. П. Лопа-
та, М. Е. Неменман, В. Я. Пыхтин, В. Н. Тикменов; Под ред. Л. Н. Пресну-
хина.— М.: Высш. шк„ 1988.— Кн. 5.— 143 с.
7. Персональные компьютеры единой системы/А. П. Запольский,
В. Я- Пыхтин, А. Н. Чистяков, В. Б. Шкляр.— М.: Финансы и
статистика, 1988.— 143 с.
8. Прайс Д. Программирование на языке ПАСКАЛЬ: Практ.
руководство.— М.: Мир, 1987.— 232 с.
9. Пул Л. Работа на персональном компьютере.— М.: Мир, 1986.—
284 с.
10. Скляров В. А., Булатова И. Р. Знакомьтесь: ПАСКАЛЬ! —
А!н.: Выш. шк., 1988.— 269 с.
1 1. Скляров В. А., Лосич В. А., МикроЭВМ для всех.— Мн.:
Выш. шк., 1989.— 253 с.
12. Уэйт М., Прата С., Мартин Д. Язык СИ: Руководство для
начинающих.— М.: Мир, 1988.— 512 с.
13. Форсайт Р. ПАСКАЛЬ для всех.— М.: Машиностроение, 1986.—
288 с.
14. Чоговадзе Г. Г. Персональные компьютеры.— М.: Финансы
и статистика, 1989.— 208 с.
15. Юлин В. А., Булатова И. Р. Приглашение к «СИ.— Мн.:
Выш. шк., 1990.— 224 с.
16. Bradley D. К. EGA/VGA A Programmer’s Reference Guide.—
N. Y.: Intertext Publications McGraw-Hill Book Company, 1988.— 269 p.
17. Burnar S. Advanced TURBO C Programming.— Greensboro,
Penn.: North Carolina Radnor, 1988.— 327 p.
18. Duncan R. Advanced MS-DOS.— Washington: Microsoft Press,
1986,— 472 p
19. Lacobucci Ed. OS-2 Programmer’s Guide.— Berkeley, Ca.:
Osborn Me. Grow-Hill, 1989.— 999 c.
20. Stevens R. T. Graphics Programming in C.— Redwood City,
Ca.: M&T Publishing. Inc., 1988. - 639 p.
ПРЕДМЕТНЫЙ УКАЗАТЕЛЬ*
Адаптер (контроллер) 37
— одноцветный (монохром-
ный 37
— периферийный 14
— цветной графический 37
Аргументы 189
ASCII-код 33
— — расширенный 33, 79
— — управляющий 449, 450
Ассемблер 247
Базовая система ввода-вывода
(BIOS) 14, 100, 406
Байт атрибутов 39
Библиотеки 334—373
Битовая карта (битовый план) 45
Блок 31 9
— начальной загрузки («загруз-
чик») 101, 102
— системный 7
Вектор 28
Вершина 252
Вложенные конструкции 203
Вызов подпрограмм 183
Выражения 167, 171, 273
- адресные 273
— числовые 273
Графопостроители 88—93
Группа 278
Декларативный подход 224
Джойстик 98
Директорий 69, 100
— корневой 69
— нижнего уровня (поддиректо-
рий) 70
Дискета 66
Дисплей 37, 41
— аналоговый 41
— композиционный 41
— цифровой 41
Драйвер 100, 134—141
ESC-код 79
ESC-последовательности 79, 138,
139
Заголовок драйвера 135
Записи с вариантами 178
Запись 176, 207
Зарезервированное слово 270
Идентификатор 163, 191
Имя логическое 210
— массива 206
— составное 177
Инициализация 214
Инструкция 171, 172, 189
— вложенная 172, 204
Интегрированные среды 309
Интерпретатор команд 103
Источник 109
Каналы ввода-вывода 18—28
— — — параллельные 18
— — — последовательные 18^
83—88
Клавиатура 32—38
Клавиши алфавитно-цифровые и
знаковые 32
— вспомогательные 32
— служебные для Смены регист-
ров и модификации кодов 32
— — для фиксации регистров 32
— — для управления перемеще-
нием курсора и редактированием
32
Составила С. Ю. Липец.
457
— функциональные 32
Класс 277
Кластер 70
Командный процессор 100, 101,
103
Команды 313
- ОС 103
— резидентные 109—114
Конец строки «жесткий» 147
— — «мягкий» 147
Конкатенация (сцепление) 109,
292
Контроллер дискет 70
- НГМД 71—78
— экрана 37
Корневой каталог 104
Лексема 270
Логический сегмент программы
276
Макрокоманды 292—295
Макропроцессор (препроцессор)
216—218
Манипулятор 98
— типа «мышь» 98
Мантисса 163, 192
Маршрут 106
Массив 174, 175, 205
Метка 204, 272
Метки случаев 172
Микропроцессор 7
Мнемоника 272
Множество 175
— базовое 175
— Пустое 175
Обработчик прерываний 155 , 295—
300
Обрамление форматирующее 68
Операнды 167, 273
Оперативная память 10, 14—18
Операторные скобки 170
Операторы 167—169
— исполняемые 271
— неисполняемые 271
Операции бинарные 199
— унарные 199
— — декремента 199
— — инкремента 199
Операционная система 14
-----MS-DOS 99—141
Операция запятая 202
— тернарная 199
Описание переменной 191
Определение переменной 191
Палитра 387
Параграф 10
Переключатели 314
Переменная управляющая 170, 201
Переменные автоматические 213
— внешние 213
— глобальные 194
— локальные 1 94
— регистровые 214
— статические 213
Персональная ЭВМ 7
Подкаталог 104
Поле 209, 247
— кода операции 247
Порты 18—28
Порядок 163, 192
Правило вывода 224
Прерывания 28, 29, 252, 405—448
— аппаратные 28, 405, 414—422
— базовой системы ввода-вывода
413, 414
— внешние 252
— внутренние 252
— логические (процессорные) 405
— операционной системы 436—
448
— программные 405
Префикс-повторитель 261
Префиксы 272
Принтеры 78—83
Пробелы «жесткие» 147
— «мягкие» 147
Программы типа СОМ 130—139
---EXE 130—139
— фильтры 406
Прототип функции 214
Профессиональный текстовой ре-
дактор X-Writer 142—160
Процедура 182, 278
Псевдопеременные 218
Регистры общего назначения 10
— программно-доступные 8
Режим адресации 247
— — данных базовый индексный
248
— — — — — относительный
248
— — — непосредственный 247
— — — прямой 247
458
— — - регистровый 247
— — — — косвенный 247
— — — — относительный 248
— — перехода 249
— — — внутрисегментного пря-
мого 249
— — — — косвенного 249
— — — межсегментного косвен-
ного 249
— — — — прямого 249
— вывода информации графиче-
ской 37, 38
— — — монохромный 39
— — — псевдографический 40
— — — текстовой 39
— — — цветной 38, 39
Рекурсия 184, 232
Световое перо 98
Сегмент 9
Сектор 66
Селектор 172, 204
Система ТУРБО СИ 309
Системы программирования ин-
струментальные 309—333
Скэн-код 33
— — дополнительный 33
Смесь 209
Спецификация файла 107
Списки 233
Способ разметки дорожек на сек-
торы программный 67
— — — — — фиксированный
(аппаратный) 67
Стек 251
Страница 40, 385
Стратегия 135
Строка информационная 144, 145
— курсора конечная 60
— — начальная 60
Счетчик ячеек (адресов) 280
Таблица разделов 71
— размещения файлов 69—71
Тело макрокоманды (макроопре-
деление) 292
— программы 189
— цикла 170, 201. 203
Тил процедурный 224
Типы данных структурированные
173— 182, 204—211, 236—240
— интервальные 164
— перечисляемые 164
Указатели 200, 206
Унификация 225
Уровень представления и обра-
ботки сигналов логический 33—
35
— — — — физический 32, 33
— — — — функциональный 36,
37
Условие возобновления цикла 171
Условная трансляция 293
Установка драйвера 135
Устройства блочные 135
— для съема графической ин-
формации 93—97
— символьные 135
Утилита ОС 101
Утилиты 104
— внешние 114—124
Файл 99, 179, 210—216
Файловая система 99, 104—109
Факт 224
Формат данных логический 68
— — физический 68
Функции ОС 183, 211
Цель 225
Цилиндр 68
Часть командного процессора по-
лурезидентная 103
— — — резидентная 103
Шаблон 107
Язык алгоритмический ПАСКАЛЬ
161 - 188
---СИ 189—223
— ассемблера 247—308
— логического программирования
ПРОЛОГ 224—246
ОГЛАВЛЕНИЕ
Предисловие ................................................. 3
Условные сокращения ......................................... 6
1. ПЕРСОНАЛЬНЫЕ ЭВМ
1.1. Назначение, состав и технические характеристики ПЭВМ ... 7
1.2. Аппаратные и программные средства ПЭВМ...................8
1.3. Распределение оперативной памяти........................14
1.4. Каналы и порты ввода-вывода.............................18
1.5. Прерывания..............................................28
1.6. Системные ресурсы.......................................30
2. ПЕРИФЕРИЙНЫЕ УСТРОЙСТВА ПЭВМ
2.1. Клавиатура..............................................32
2.2. Видеодоступ.............................................37
2.3. Накопители на гибких и жестких дисках...................66
2.4. Принтеры . . . '........................................78
2.5. Ввод н вывод через последовательный канал...............83
2.6. Графопостроители ПЭВМ .... 88
2.7. Устройства для съема графической информации.............93
2.8. Манипуляторы............................................98
3. ОПЕРАЦИОННАЯ СИСТЕМА MS-DOS
3.1. Общие сведения об операционных системах .... . . 99
3.2. Структура MS-DOS.......................................100
3.3. Файловая система..................................... .104
3.4. Резидентные команды и внешние утилиты........... .109
3.5. Командные файлы и конфигурирование системы.............124
3.6. Программы типа СОМ и ЕХЕ...............................130
3.7. Устанавливаемые драйверы устройств.....................134
3.8. Драйвер ANSI.SYS.ESC-последовательности ...............138
4. ТЕКСТОВОЙ РЕДАКТОР X-WR1TER
4.1. Загрузка и подготовка к работе . . ................142
4.2. Организация экрана редактора...........................144
4.3. Структура редактируемого текста . ................147
4.4. Команды перемещения курсора . . . ............148
4.5. Выбор шрифта....................... . ............149
4.6. Описание команд редактора............................ 149
460
5. АЛГОРИТМИЧЕСКИЙ ЯЗЫК ПАСКАЛЬ
5.1. Программы и данные................. ... . .161
5.2. Ввод и вывод................ . .... . 165
5.3. Операторы и выражения................. ... . 167
5.4. Структурированные типы данных . . . 173
5.5. Процедуры и функции......... . 182
5.6. Динамические структуры данных . 186
6. АЛГОРИТМИЧЕСКИЙ ЯЗЫК СИ
6.1. Программы и данные . . . .... 189
6.2. Ввод и вывод....................... . . .... 196
6.3. Операторы и выражения ... . .... 199
6.4. Структурированные типы данных . . . . . . . 204
6.5. Функции................... . . . ....211
6.6. Макропроцессор..................................... 216
6.7. Программирование низкого уровня 218
6.8. Стиль программирования 220
7. ЯЗЫК ПРОЛОГ
7.1. Программы и данные 224
7.2. Ввод и вывод . . . 230
7.3. Списки и рекурсия .... 231
7.4. Арифметические и логические операции 235
7.5. Структурированные типы данных . . 236
7.6. Модульное программирование . 240
7.7. Стандартные предикаты . . 242
8. ЯЗЫК АССЕМБЛЕРА
8.1. Общие сведения ......... 247
8.2. Система команд микропроцессора Intel 8086 253
8.3. Базовые конструкции языка . . 270
8.4. Система программирования MASM 279
8 5. Объединение объектных модулей . . 288
8.6. Макрокоманды .... . 292
8.7. Обработка прерываний.......... . 295
8.8. Интерфейс с языками высокого уровня . 300
8.9. Драйвер символьного устройства .... . 304
9. ИНСТРУМЕНТАЛЬНЫЕ СИСТЕМЫ ПРОГРАММИРОВАНИЯ
9.1. Общие сведения . . . 309
9.2. Работа с файлами . . . . . . . .315
9.3. Подготовка и редактирование текстов программ . . . .317
9.4. Настройка системы.................... .... ... 320
9.5. Компиляция, отладка и выполнение программ . . . . 325
9.6. Взаимодействие программ ... . . . 330
10. БИБЛИОТЕКИ
10.1. Общие сведения . . . 334
10.2. Стандартные функции языка СИ . ... 337
10.3. Стандартные процедуры и функции языка ПАСКАЛЬ 364
461
11. РАБОТА С ГРАФИКОЙ
11.1. Общие сведения...............................374
1 1.2. Подпрограммы для получения изображения на экране . . . 380
11.3. Подпрограммы для установки параметров изображения . . . 387
11.4. Подпрограммы для получения параметров изображения . . 394
11.5. Отображение псевдографической информации.....398
12. ПРЕРЫВАНИЯ MS-DOS
12.1. Общие сведения...............................405
12.2. Средства для работы с прерываниями...........408
12.3. Прерывания базовой системы ввода-вывода......413
12.4. Прерывания операционной системы ... . ... 436
Приложение. .. ......... .... . 449
Литература . ..............................456
Предметный указатель.......................................... 457
Справочное издание
Скляров Валерий Анатольевич
ПРОГРАММНОЕ И ЛИНГВИСТИЧЕСКОЕ
ОБЕСПЕЧЕНИЕ ПЕРСОНАЛЬНЫХ ЭВМ
СИСТЕМЫ ОБЩЕГО НАЗНАЧЕНИЯ
Справочное пособие
Художник переплета В. А Ярошевич
Художественный редактор Ю С. Сергачев
Технический редактор И П Тихонова
Корректоры И. Б. Назарева, Т Д' Хваль, Л А. Ер-
кович
ИВ № 3196
Сдано в набор II 04.91 Подписано п печать 2(1 11.91 Формат
84X108/32. Бумага тип. № 2 Гарнитура литературная. Высокая
печать. Усл печ. л. 24,36. Усл. кр-отт 24,36 Уч-изд. л. 24.97
Тираж 26 000 экэ. Заказ 1244. Цена 7 р
Издательство <кВышэйшая школа» Государственного комитета
Республики Беларусь по печати. 220048, Минск, проспект Маше-
рова, 1 Г
Минский ордена Трудового Красного Знамени полиграфкомбинат
МИПО им Я- Коласа 220005, Минск, ул. Красная, 23.