mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-14 10:57:08 +03:00
60e27afe74
templates: upload to svn, add to ISO/res/templates git-svn-id: svn://kolibrios.org@7544 a494cfbc-eb01-0410-851d-a64ba20cac60
5677 lines
236 KiB
HTML
5677 lines
236 KiB
HTML
<html>
|
||
<head>
|
||
<title>Документация на C--</title>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
|
||
<style>
|
||
body, a, pre {
|
||
font-family: 'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace !important;
|
||
}
|
||
a {
|
||
color: #0000ff;
|
||
}
|
||
#contents a {
|
||
font-weight: bold;
|
||
text-decoration: none;
|
||
}
|
||
h1 {
|
||
color: #F000F0;
|
||
font-size: 200%;
|
||
}
|
||
h2 {
|
||
color: #f00;
|
||
font-size: 100%;
|
||
margin-bottom: 0;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body LINK="#0000ff" VLINK="#800080">
|
||
<h1>Содержание</h1>
|
||
<pre>
|
||
<div id="contents">
|
||
<a href="#intro">1 Введение.
|
||
1.1 История создания и развития.</A>
|
||
<a href="#1.2">1.2 Что такое C--?</a>
|
||
<a href="#1.3">1.3 Как установить C--.</a>
|
||
<A name=contents2>
|
||
<a href="#2.1">2. Управление компиляцией.
|
||
2.1 Параметры командной строки компилятора C--.</a>
|
||
<a href="#2.1.1">2.1.1 /ON - Оптимизация числовых выражений.</a>
|
||
<a href="#2.1.2">2.1.2 /DE - Временное расширение разрядности переменной.</a>
|
||
<a href="#2.1.3">2.1.3 /ARGC - Альтернативный обработчик командной строки.</a>
|
||
<a href="#2.1.4">2.1.4 /OST - слияние одинаковых строковых констант.</a>
|
||
<a href="#2.1.5">2.1.5 /D - установка идентификатора в TRUE из командной строки.</a>
|
||
<a href="#2.1.6">2.1.6 /IA - упрощенный ввод ассемблерных инструкций.</a>
|
||
<a href="#2.1.7">2.1.7 /CRI - пропуск повторно включаемого файла.</a>
|
||
<a href="#2.1.8">2.1.8 /IND - импорт имен процедур из DLL.</a>
|
||
<a href="#2.1.9">2.1.9 /WS - задать имя stub файла для программ под windows.</a>
|
||
<a href="#2.1.10">2.1.10 /WBSS - разместить не инициализированные данные в отдельной секции.</a>
|
||
<a href="#2.1.11">2.1.11 /DBG - создание отладочной информации.</a>
|
||
<a href="#2.1.12">2.1.12 /J0 /J1 /J2.</a>
|
||
<a href="#2.1.13">2.1.13 /LST - Создание ассемблерного листинга.</a>
|
||
<a href="#2.1.14">2.1.14 /ENV - Сохранение адреса переменных окружения.</a>
|
||
<a href="#2.1.15">2.1.15 /CPA - Очистка post-области данных.</a>
|
||
<a href="#2.1.16">2.1.16 /W - вывод предупреждений.</a>
|
||
<a href="#2.1.17">2.1.17 /NW - Выборочное отключение типов предупреждений.</a>
|
||
<a href="#2.1.18">2.1.18 /WSI - короткая таблица импорта.</a>
|
||
<a href="#2.2">2.2 Директивы транслятора.</a>
|
||
<a href="#2.2.1">2.2.1 ?ifdef/?ifndef</a>
|
||
<a href="#2.2.2">2.2.2 ?initallvar</a>
|
||
<a href="#2.2.3">2.2.3 ?usestartup</a>
|
||
<a href="#2.2.4">2.2.4 ?startusevar</a>
|
||
<a href="#2.2.5">2.2.5 ?atexit</a>
|
||
<a href="#2.2.6">2.2.6 ?startuptomain</a>
|
||
<a href="#2.2.7">2.2.7 ?undef</a>
|
||
<a href="#2.2.8">2.2.8 ?align и ?aligncode</a>
|
||
<a href="#2.2.9">2.2.9 ?pragma</a>
|
||
<A name=contents3>
|
||
<a href="#3.1">3. Константы.
|
||
3.1 Числовые константы.</a>
|
||
<a href="#3.2">3.2 Символьные константы.</a>
|
||
<a href="#3.3">3.3 Строковые константы.</a>
|
||
<a href="#3.4">3.4 Постоянные выражения.</a>
|
||
<A name=contents4>
|
||
<a href="#4.1">4. Выражения.
|
||
4.1 Типы выражений.</a>
|
||
<a href="#4.2">4.2 Выражения типа EAX/AX/AL.</a>
|
||
<a href="#4.3">4.3 Выражения использующие получатель при вычислении выражения.</a>
|
||
<a href="#4.4">4.4 Не - EAX/AX/AL выражения.</a>
|
||
<a href="#4.5">4.5 Условные выражения.</a>
|
||
<a href="#4.5.1">4.5.1 Простые условные выражения.</a>
|
||
<a href="#4.5.2">4.5.2 Сложные условные выражения.</a>
|
||
<a href="#4.6">4.6 Изменение типа выражения при присваивании.</a>
|
||
<a href="#4.7">4.7 Вычисление в регистры EAX/AX/AL со знаком.</a>
|
||
<A name=contents5>
|
||
<a href="#5.1">5. Идентификаторы.
|
||
5.1 Формат идентификатора.</a>
|
||
<a href="#5.2">5.2 Зарезервированные идентификаторы.</a>
|
||
<a href="#5.3">5.3 Универсальные регистры для 16 и 32-битного режима.</a>
|
||
<a href="#5.4">5.4 Предопределенные идентификаторы.</a>
|
||
<A name=contents6>
|
||
<a href="#6.1">6. Переменные.
|
||
6.1 Типы переменных.</a>
|
||
<a href="#6.2">6.2 Объявление переменных.</a>
|
||
<a href="#6.3">6.3 Глобальные переменные.</a>
|
||
<a href="#6.4">6.4 Локальные переменные.</a>
|
||
<a href="#6.5">6.5 Динамические переменные и структуры.</a>
|
||
<a href="#6.6">6.6 Присваивание одного значения нескольким переменным.</a>
|
||
<a href="#6.7.1">6.7 Переменные типа float.
|
||
6.7.1 Формат переменных типа float.</a>
|
||
<a href="#6.7.2">6.7.2 Константы с плавающей точкой.</a>
|
||
<a href="#6.7.3">6.7.3 Диапазон допустимых значений.</a>
|
||
<a href="#6.7.4">6.7.4 Математические операции.</a>
|
||
<a href="#6.7.5">6.7.5 Преобразования типов.</a>
|
||
<a href="#6.7.6">6.7.6 Операции сравнения.</a>
|
||
<a href="#6.7.7">6.7.7 Сравнение переменных типа float с 32-битным регистром.</a>
|
||
<a href="#6.8">6.8 Указатели.</a>
|
||
<A name=contents7>
|
||
<a href="#7.1">7. Адресация.
|
||
7.1 Относительная адресация.</a>
|
||
<a href="#7.2">7.2 Абсолютная адресация.</a>
|
||
<A name=contents8>
|
||
<a href="#8.1.1">8. Работа с блоками данных.
|
||
8.1 Структуры.
|
||
8.1.1 Что такое структуры.</a>
|
||
<a href="#8.1.2">8.1.2 Синтаксис.</a>
|
||
<a href="#8.1.3">8.1.3 Инициализация структур при объявлении.</a>
|
||
<a href="#8.1.4">8.1.4 Инициализация структуры при выполнении программы.</a>
|
||
<a href="#8.1.5">8.1.5 Операции с элементами структур.</a>
|
||
<a href="#8.1.6">8.1.6 Вложенные структуры.</a>
|
||
<a href="#8.1.7">8.1.7 Отображение тега структуры на блок памяти.</a>
|
||
<a href="#8.1.8">8.1.8 Битовые поля структур.</a>
|
||
<a href="#8.2">8.2 Объединения.</a>
|
||
<a href="#8.3">8.3 Команды FROM и EXTRACT.</a>
|
||
<A name=contents9>
|
||
<a href="#9.1">9. Операторы.
|
||
9.1 Условные инструкции.</a>
|
||
<a href="#9.2">9.2 Циклы do{} while.</a>
|
||
<a href="#9.3">9.3 Циклы loop, LOOPNZ, loopnz.</a>
|
||
<a href="#9.4">9.4 Цикл while, WHILE.</a>
|
||
<a href="#9.5">9.5 Цикл for, FOR.</a>
|
||
<a href="#9.6">9.6 Оператор переключатель switch.</a>
|
||
<a href="#9.7">9.7 Оператор перехода goto, GOTO.</a>
|
||
<a href="#9.8">9.8 Оператор разрыва break, BREAK.</a>
|
||
<a href="#9.9">9.9 Оператор продолжения continue, CONTINUE.</a>
|
||
<a href="#9.10">9.10 Логическое объединение условий.</a>
|
||
<a href="#9.11">9.11 Переход через циклы.</a>
|
||
<a href="#9.12">9.12 Инвертирование флага проверки условий.</a>
|
||
<a href="#9.13">9.13 Вычисление выражения, а затем проверка условия.</a>
|
||
<a href="#9.14">9.14 Проверка битов при операции сравнения.</a>
|
||
<a href="#9.15">9.15 Оператор перестановки.</a>
|
||
<a href="#9.16">9.16 Оператор отрицания.</a>
|
||
<a href="#9.17">9.17 Оператор инверсии.</a>
|
||
<a href="#9.18">9.18 Специальные условные выражения.</a>
|
||
<a href="#9.19">9.19 Символ $ - вставляет текущий адрес программы.</a>
|
||
<a href="#9.20">9.20 Ключевое слово static и оператор ::.</a>
|
||
<a href="#9.21">9.21 Оператор sizeof.</a>
|
||
<a href="#9.22">9.22 Метки перехода.</a>
|
||
<A name=contents10>
|
||
<a href="#10.1">10. Ассемблер.
|
||
10.1 Поддержка команд ассемблера.</a>
|
||
<a href="#10.2">10.2 Ключевое слово asm.</a>
|
||
<a href="#10.3">10.3 Префикс dup - повторение инструкций DB/DW/DD.</a>
|
||
<a href="#10.4">10.4 Инструкции процессора Pentium III.</a>
|
||
<A name=contents11>
|
||
<a href="#11.1">11. Процедуры.
|
||
11.1 Типы процедур, функций и макрокоманд.</a>
|
||
<a href="#11.2">11.2 Стековые процедуры.</a>
|
||
<a href="#11.3">11.3 Регистровые процедуры.</a>
|
||
<a href="#11.4">11.4 Динамические процедуры.</a>
|
||
<a href="#11.4.1">11.4.1 Установка динамической процедуры в определенное место программы.</a>
|
||
<a href="#11.5">11.5 inline-процедуры.</a>
|
||
<a href="#11.5.1">11.5.1 Другое применение inline.</a>
|
||
<a href="#11.6">11.6 Процедуры обработки прерываний.</a>
|
||
<a href="#11.7">11.7 Замена return на goto.</a>
|
||
<a href="#11.8">11.8 Возвращаемые значения.</a>
|
||
<a href="#11.9">11.9 Объявление параметров в регистровых процедурах.</a>
|
||
<a href="#11.10">11.10 Объявление параметров в стековых процедурах.</a>
|
||
<a href="#11.11">11.11 Использование макрокоманд.</a>
|
||
<a href="#11.12">11.12 Передача параметров в стековые процедуры через регистры.</a>
|
||
<a href="#11.13">11.13 Вызов процедур с адресом в регистре.</a>
|
||
<a href="#11.14">11.14 Встоенные в компилятор процедуры.</a>
|
||
<a href="#11.14.1">11.14.1 Процедуры ABORT, ATEXIT и EXIT.</a>
|
||
<a href="#11.14.2">11.14.2 Процедуры inp/inportb, inport, inportd, outp/outportb, outport и
|
||
outportd.</a>
|
||
<a href="#11.14.3">11.14.3 Процедуры для работы с вещественными числами.</a>
|
||
<a href="#11.15.1">11.15 Классы.
|
||
11.15.1 Объявление процедур в структурах.</a>
|
||
<a href="#11.15.2">11.15.2 Наследование.</a>
|
||
<a href="#11.15.3">11.15.3 Наследование процедур.</a>
|
||
<A name=contents12>
|
||
<a href="#12.1">12. Типы выходных файлов.
|
||
12.1 Выходные файлы типа COM.</a>
|
||
<a href="#12.2">12.2 Выходные файлы типа EXE.</a>
|
||
<a href="#12.3">12.3 Выходной файл *.EXE с моделью памяти tiny.</a>
|
||
<a href="#12.4">12.4 Объектный выходной файл OBJ.</a>
|
||
<a href="#12.5.1">12.5 COM файл symbiosis.
|
||
12.5.1 СИМБИОЗ - что это такое?</a>
|
||
<a href="#12.5.2">12.5.2 Как это делать.</a>
|
||
<a href="#12.5.3">12.5.3 Использование.</a>
|
||
<a href="#12.5.4">12.5.4 Злоупотребления.</a>
|
||
<a href="#12.6">12.6 SYS - драйверы устройств.</a>
|
||
<a href="#12.7">12.7 Компиляция кода расширителей ROM-BIOS.</a>
|
||
<a href="#12.8.1">12.8 32-битные файлы.
|
||
12.8.1 32-битный код под DOS.</a>
|
||
<a href="#12.8.2">12.8.2 32-битный код под Windows.</a>
|
||
<a href="#12.8.3">12.8.3 Вызов API процедур по ординалам.</a>
|
||
<a href="#12.8.4">12.8.4 Создание DLL под Windows.</a>
|
||
<a href="#12.8.5">12.8.5 Инициализация DLL при загрузке.</a>
|
||
<a href="#12.8.6">12.8.6 Компиляция ресурсов.</a>
|
||
<a href="#12.9">12.9 Выходные файлы для MeOS.</a>
|
||
<A name=contents13>
|
||
<a href="#13.1">13. Приложения.
|
||
13.1 Поиск включаемых файлов.</a>
|
||
<a href="#13.2">13.2 Регистры, которые должны быть сохранены.</a>
|
||
<a href="#13.3">13.3 C--.ini файл.</a>
|
||
<a href="#13.4">13.4 startup.h-- файл.</a>
|
||
<a href="#13.5">13.5 mainlib.ldp файл.</a>
|
||
<a href="#13.6">13.6 C-- символы.</a>
|
||
</div>
|
||
|
||
|
||
<h2 id=intro>1. Вступление.
|
||
|
||
1.1 История создания и развития.
|
||
</h2>
|
||
|
||
Автором языка SPHINX C-- является Peter Cellik (CANADA). Последняя
|
||
авторская версия SPHINX C-- v0.203 от 28.Oct.96. К сожалению автор
|
||
отказался от дальнейшего развития языка. С 1998 года, уже почти умерший
|
||
проект, подхватил Михаил Шекер (Россия). Изначально компилятор был freeware
|
||
(и даже greenware, как его называл Peter Cellik). Таким статус компилятора
|
||
остался и поныне.
|
||
|
||
Первоначально компилятор мог создавать только *.com файлы и был
|
||
рассчитан на создание небольших demo-программ и резидентов (TSR). В
|
||
дальнейшем возможности компилятора расширялись, так как этого требовало
|
||
наше бурное время.
|
||
|
||
При развитии компилятора, было стремление придерживаться следующих
|
||
принципов:
|
||
|
||
1. Максимально возможная совместимость синтаксиса с последней версией
|
||
компилятора написанного Peter Cellik. Это давало возможность с минимальными
|
||
затратами (а чаще всего без всяких затрат) адаптировать программы,
|
||
написанные для 0.203 версии компилятора, к последней на этот момент версии
|
||
компилятора.
|
||
|
||
2. Сблизить синтаксис компилятора со стандартным языком C. Это могло
|
||
значительно облегчить перенос программ написанных на C.
|
||
|
||
3. Также прилагались усилия, для того, чтобы человек знающий только
|
||
ассемблер мог бы с минимальными затратами освоить C--.
|
||
|
||
Вот эти, зачастую противоречащие друг другу принципы, влияли на выбор
|
||
реализации возможностей компилятора. Насколько это удалось - судить Вам.
|
||
|
||
Если у Вас есть предложения и идеи по улучшению компилятора - пишите.
|
||
Мой e-mail <a href="mailto:sheker@mail.ru">sheker@mail.ru</a> . Я с удовольствием выслушаю Ваши предложения, но
|
||
не гарантирую, что все они будут реализованы. Если реализовывать все
|
||
поступающие предложения, то компилятор превратится в свалку. Но если Ваше
|
||
предложение будет ценным (на мой взгляд, так что Вам придется свое
|
||
предложение хорошо аргументировать) и его будет возможным реализовать, оно
|
||
без сомнения найдет место в компиляторе.
|
||
<a href="#contents"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=1.2>
|
||
1.2 Что такое C--?
|
||
</h2>
|
||
|
||
C-- был разработан, для того чтобы строить маленькие и быстрые
|
||
программы. Это наиболее подходит для создания резидентных программ (TSR),
|
||
программ, требующих обработку прерываний или программ у которых ограничены
|
||
ресурсы.
|
||
|
||
C-- занимает промежуточное положение между си и ассемблером. В связи с
|
||
этим промежуточным положением, Вам, для того чтобы писать программы на C--,
|
||
необходимо знать и ассемблер и си. Если Вам надоело возиться с огромными
|
||
ассемблерными листингами, а излишняя строгость языка C Вас угнетает, то этот
|
||
язык для ВАС.
|
||
|
||
Сейчас компилятор C-- может создавать 32-битные программы под Windows
|
||
(EXE-файлы формата PE) и 32-битные программы под DOS (LE-формат). Имеет
|
||
встроенный компилятор ресурсов и дизассемблер для генерации листинга
|
||
откомпилированного файла. Поддерживает ассемблерные инструкции процессора
|
||
Pentium III и ассемблерные инструкции FPU. Компилятор может генерировать
|
||
отладочную информацию совместимую с отладчиками фирмы Borland. Компилятор
|
||
может создавать объектные файлы (obj), но только для DOS программ.
|
||
|
||
C-- разработан только для использования на компьютерах с процессорами
|
||
совместимыми с семейством 80x86. Компилятор может работать только с
|
||
операционными системами DOS и семейством Windows.
|
||
<a href="#contents"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=1.3>
|
||
1.3 Как установить C--.
|
||
</h2>
|
||
|
||
Компилятору C-- для работы нужны совсем незначительные ресурсы:
|
||
процессор 386 или лучше, чуть более 1 Мб дискового пространства и 4Мб
|
||
оперативной памяти. Компилятор может быть установлен на компьютеры с
|
||
операционной системой Windows 95 или лучше. Компилятор также может работать
|
||
в среде чистого DOS. В основном пакете компилятора находится 32-битная DOS
|
||
версия компилятора. На сайте <a href="http://sheker.chat.ru">http://sheker.chat.ru</a> или
|
||
<a href="http://c--sphinx.narod.ru">http://c--sphinx.narod.ru</a> можно найти и консольную версию компилятора.
|
||
Консольная версия компилятора может работать только в среде Windows, но
|
||
она, в отличие от DOS версии, может работать с длинными именами исходных
|
||
файлов.
|
||
|
||
Установить компилятор C-- на Ваш компьютер очень просто. Предположим,
|
||
что Вы решили установить C-- на диск C. Создайте на диске C директорию
|
||
(папку) с именем <b>C--</b> или с другим, удобным и понятным для Вас именем
|
||
(например, ДОСовской командой: <b>MD C--</b> или другим доступным Вам способом).
|
||
Затем с сайта <a href="http://sheker.chat.ru">http://sheker.chat.ru</a> или <a href="http://c--sphinx.narod.ru">http://c--sphinx.narod.ru</a> скачайте
|
||
файлы full_c--.zip и ful_c--2.zip и разархивируйте их в этой директории.
|
||
Затем в файле autoexec.bat можно прописать путь к директории с
|
||
компилятором. И все. Компилятор готов к работе. Если Вы добавляли путь к
|
||
компилятору в файл autoexec.bat, то Вам придется перегрузить операционную
|
||
систему.
|
||
|
||
Переменная окружения для компилятора C-- задается либо из командной
|
||
строки либо из командного файла (лучше всего ее прописать в autoexec.bat).
|
||
Эта переменная должна указывать компилятору, где находятся его библиотечные
|
||
файлы. Пример:
|
||
|
||
<b>set C--=c:\c--\lib</b>
|
||
|
||
Большой необходимости в переменной окружения для сегодняшней версии
|
||
компилятора нет. Существует несколько других способов, указать компилятору
|
||
место расположения библиотек. Поэтому определять или не определять
|
||
переменную окружения дело вашего вкуса и привычек.
|
||
<a href="#contents"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1>
|
||
2. Управление компиляцией.
|
||
|
||
2.1 Параметры командной строки компилятора C--.
|
||
</h2>
|
||
|
||
Формат командной строки вызова компилятора C--:
|
||
|
||
C-- [Параметры] [ИМЯ INI ФАЙЛА] [ИМЯ ИСХОДНОГО ФАЙЛА]
|
||
|
||
Имя исходного файла можно задавать без расширения. Компилятор ищет
|
||
файл с расширением <b>c--, cmm, c</b>.
|
||
|
||
Параметры выделяются предшествующим символом <b>/</b> или <b>-</b>.
|
||
Инвертировать функцию опции можно завершающим символом <b>-</b>.
|
||
|
||
Список поддерживаемых параметров:
|
||
|
||
<b>/0</b> использовать только команды 8086/8088 процессора (установлено
|
||
по умолчанию при компиляции 16-битных программ).
|
||
<b>/1</b> использовать команды 80186 процессора.
|
||
<b>/2</b> использовать команды и оптимизацию для 80286 процессора.
|
||
<b>/3</b> использовать команды и оптимизацию для 80386 процессора.
|
||
(установлено по умолчанию для 32-битных программ).
|
||
<b>/4</b> использовать команды и оптимизацию для 80486 процессора.
|
||
<b>/5</b> использовать команды и оптимизацию для Pentium процессора.
|
||
<b>/6</b> использовать команды и оптимизацию для Pentium MMX процессора.
|
||
<b>/7</b> использовать команды и оптимизацию для Pentium Pro процессора.
|
||
<b>/8</b> использовать команды и оптимизацию для Pentium II процессора.
|
||
<b>/9</b> использовать команды и оптимизацию для Pentium III процессора
|
||
(пока не реализовано из-за отсутствии информации).
|
||
<b>/A</b> выравнивание данных на четный адрес
|
||
по умолчанию разрешено, поддерживает инверсию
|
||
<b>/AC</b> выравнивание адреса начала циклов
|
||
по умолчанию отключено, поддерживает инверсию
|
||
имеет смысл только на процессорах Pentium+
|
||
<b>/AL</b>=## установить значение байта заполнения при выравнивании данных
|
||
по умолчанию 0.
|
||
<b>/AP</b> выравнивание адреса начала процедур.
|
||
по умолчанию отключено, поддерживает инверсию
|
||
имеет смысл только на процессорах Pentium и лучше
|
||
<b>/ARGC</b> вставить блок разбора командной строки
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/AS</b> выравнивание в структурах.
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/AT</b> вставить блок поддержки <b>ATEXIT</b> процедуры
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/C</b> вставить блок игнорирования <b>CTRL-C</b>
|
||
по умолчанию отключен, поддерживает инверсию
|
||
имеет смысл только под DOS программы
|
||
<b>/CRI</b> проверять включаемые файлы на повторную загрузку
|
||
по умолчанию включено, поддерживает инверсию
|
||
<b>/CPA</b> очистка post-области данных
|
||
<b>/D32</b> создать EXE файл (32 битный код под DOS)
|
||
по умолчанию COM
|
||
<b>/D</b>=idname определить идентификатор для условной компиляции
|
||
по умолчанию нет
|
||
<b>/DBG</b> генерировать отладочную информацию
|
||
по умолчанию нет
|
||
<b>/DE</b> временное расширение разрядности после умножения
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/DLL</b> создать DLL для Windows32
|
||
по умолчанию COM
|
||
<b>/ENV</b> сохранение адреса переменных окружения
|
||
<b>/EXE</b> создать EXE файл для DOS (модель SMALL)
|
||
по умолчанию COM
|
||
<b>/HELP /H /?</b> справка, эта информация
|
||
<b>/IA</b> имена ассемблерных инструкций являются идентификаторами
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/IND</b>=name импорт имен из файла <b>name</b>.
|
||
<b>/IP</b>=path задать путь поиска включаемых файлов
|
||
по умолчанию нет
|
||
<b>/IV</b> инициализировать все переменные
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/J0</b> не делать начальный jump на main()
|
||
по умолчанию отключено, поддерживает инверсию
|
||
В COM-файлах не создает jmp на main. В остальных не создается
|
||
блок начальной инициализации программы, а управление
|
||
передается сразу на main.
|
||
<b>/J1</b> делать короткий jump на main()
|
||
по умолчанию нет
|
||
имеет смысл только в COM-файлах
|
||
<b>/J2</b> делать jump на main()
|
||
по умолчанию да, поддерживает инверсию
|
||
имеет смысл только в COM-файлах
|
||
<b>/LAI</b> список поддерживаемых ассемблерных инструкций
|
||
<b>/LRS</b> загружать числовые константы через стек.
|
||
по умолчанию да, поддерживает инверсию
|
||
<b>/LST</b> создать ассемблерный листинг
|
||
<b>/ME</b> показать мой адрес и имя
|
||
<b>/MEOS</b> создать исполняемый файл для MeOS
|
||
по умолчанию COM
|
||
<b>/MER</b>=## установить максимальное число ошибок
|
||
по умолчанию 16
|
||
<b>/MIF</b>=file определить имя главного компилируемого файла
|
||
<b>/NS</b> запретить подключать stub файлов
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/NW</b>=## выборочное отключение предупреждений
|
||
<b>/OBJ</b> создать OBJ файл
|
||
только 16 битный код.
|
||
по умолчанию COM
|
||
<b>/OC</b> оптимизировать по размеру кода
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/ON</b> оптимизация чисел
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/OS</b> оптимизация по скорости выполнения
|
||
по умолчанию да, поддерживает инверсию
|
||
<b>/OST</b> оптимизация строковых идентификаторов
|
||
по умолчанию отключено, поддерживает инверсию
|
||
<b>/P</b> вставить блок разборки командной строки
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/R</b> вставить блок уменьшающий размер доступной памяти.
|
||
по умолчанию да, поддерживает инверсию
|
||
имеет смысл только в DOS-файлах
|
||
<b>/S</b>=##### установить размер стека
|
||
по умолчанию 2048
|
||
<b>/SA</b>=#### начальное смещение адреса запуска программы
|
||
имеет смысл только в COM-файлах, по умолчанию 0x100
|
||
<b>/SOBJ</b> создать ведомый OBJ файл
|
||
по умолчанию COM
|
||
<b>/STM</b> перенести блок startup кода в процедуру main
|
||
по умолчанию нет, поддерживает инверсию
|
||
имеет смысл только в COM-файлах
|
||
<b>/SUV</b>=#### начальный адрес не инициализированных переменных, при
|
||
использовании ими startup кода.
|
||
имеет смысл только в COM-файлах, по умолчанию равен /SA
|
||
<b>/SYM</b> надстройка для COM файла
|
||
по умолчанию COM
|
||
<b>/SYS</b> создать драйвер устройств (SYS)
|
||
по умолчанию COM
|
||
<b>/TEXE</b> создать EXE файл для DOS (модель TINY)
|
||
по умолчанию COM
|
||
<b>/UL</b> использовать lea при оптимизации сложения регистров.
|
||
по умолчанию да, поддерживает инверсию
|
||
<b>/UST</b> использовать startup код для переменных.
|
||
имеет смысл только в COM-файлах
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/W</b> разрешить предупреждения
|
||
по умолчанию нет, поддерживает инверсию
|
||
<b>/W32</b> создать EXE файл для Windows32 GUI
|
||
по умолчанию COM
|
||
<b>/W32C</b> создать EXE файл для Windows32 console
|
||
по умолчанию COM
|
||
<b>/WBSS</b> помещать не инициализированные данные в отдельную секцию.
|
||
по умолчанию для /w32 разрешено, для остальных запрещено.
|
||
поддерживает инверсию
|
||
<b>/WF</b>=file перенаправить вывод предупреждений в файл.
|
||
по умолчанию нет
|
||
<b>/WFA</b> использовать быстрые вызовы API процедур
|
||
по умолчанию да, поддерживает инверсию
|
||
только под windows
|
||
<b>/WFU</b> создавать таблицу перемещений (для Windows32)
|
||
по умолчанию нет, поддерживает инверсию
|
||
только под windows
|
||
для DLL устанавливается в да
|
||
<b>/WIB</b>=##### установить адрес image base
|
||
по умолчанию 0x400000
|
||
<b>/WMB</b> создавать Windows-файл с единым блоком
|
||
по умолчанию да, поддерживает инверсию
|
||
только под windows
|
||
для DLL устанавливается в нет
|
||
<b>/WORDS</b> выдать список зарезервированных идентификаторов
|
||
<b>/WS</b>=name указывает имя файла используемого в качестве <b>stub</b> под windows.
|
||
<b>/X</b> запретить вставлять в код <b>SPHINXC--</b> сигнатуру
|
||
по умолчанию разрешено, поддерживает инверсию
|
||
отключается если есть <b>J0</b>
|
||
|
||
Примечание: выражение <i>поддерживает инверсию</i> означает, что для данной
|
||
опции можно использовать и противоположное значение с помощью символа <b>-</b>
|
||
после опции. Пример:
|
||
|
||
<b>/WFA-</b>
|
||
|
||
Параметры командной строки можно писать как большими, так и
|
||
маленькими буквами.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.1>
|
||
2.1.1 /ON - Оптимизация числовых выражений.
|
||
</h2>
|
||
|
||
При включении в командную строку опции <b>/ON</b> или в файл C--.INI строчки
|
||
<b>ON</b>, компилятор будет анализировать операции над числами и где это
|
||
можно, сокращать число операций. Например:
|
||
|
||
Строка до оптимизации | После оптимизации
|
||
-----------------------------------------------
|
||
AX = var + 7 - 3; | AX = var + 4;
|
||
AX = var * 2 * 5; | AX = var * 10;
|
||
AX = var * 2 / 4; | AX = var / 2;
|
||
AX = var * 10 / 2; | AX = var * 5;
|
||
AX = var / 2 / 3; | AX = var / 6;
|
||
AX = var / 4 * 8; | AX = var * 2;
|
||
AX = var / 16 * 16; | AX = var;
|
||
|
||
Возможные отрицательные последствия:
|
||
Применение этой оптимизации может иметь и негативные последствия.
|
||
Например, если Вам нужно выровнять значение переменной на границу
|
||
параграфа, Вы напишите строку:
|
||
|
||
var = var / 16 * 16;
|
||
|
||
но после оптимизации будет
|
||
|
||
var = var;
|
||
|
||
т.е. выравнивание не будет произведено. Этого можно избежать, если
|
||
разбить это выражение на два:
|
||
|
||
var = var / 16;
|
||
var = var * 16;
|
||
|
||
тогда оптимизация не будет произведена. Но для получения более
|
||
компактного кода лучше будет записать так:
|
||
|
||
AX = var;
|
||
AX = AX / 16;
|
||
AX = AX * 16;
|
||
var = AX;
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.2>
|
||
2.1.2 /DE - Временное расширение разрядности переменной.
|
||
</h2>
|
||
|
||
Как известно, после умножения может произойти переполнение, т.е
|
||
разрядность результата может превысить разрядность исходных операндов и
|
||
произойдет искажение результата. Частично решить эту проблему Вам поможет
|
||
опция командной строки <b>/DE</b> или строка <b>DE</b> в файле C--.INI. После команды
|
||
умножения компилятор будет просматривать остаток строки и если обнаружит,
|
||
что расширение разрядности может быть востребовано (востребовать
|
||
расширенную разрядность могут операции деления и вычисления остатка), то
|
||
будут приняты меры по ее сохранению. Например:
|
||
|
||
a = b*c+d/e; //здесь будет включена поддержка расширения разрядности
|
||
a = b*c+d*e; //здесь поддержки расширения разрядности не будет.
|
||
|
||
Однако применение этой опции может иметь и негативные последствия.
|
||
Покажу это на примере:
|
||
|
||
пусть имеется выражение
|
||
|
||
a = b * c / d;
|
||
|
||
если значения переменных b = 0xC000, c = 0x1000, d=0x10, после запуска
|
||
такая программа зависнет с сообщением о том, что произошло переполнение
|
||
при делении.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.3>
|
||
2.1.3 /ARGC - Альтернативный обработчик командной строки.
|
||
</h2>
|
||
|
||
Отличие этого обработчика командной строки от <b>parsecommandline</b>
|
||
заключается в том, что при вызове <b>PARAMSTR(0)</b>; Вы получите адрес строки в
|
||
которой указан путь и имя запущенной программы. Следующие вызовы этой
|
||
процедуры с увеличивающимся параметром будут возвращать адреса слов
|
||
командной строки. А вызов процедуры <b>PARAMCOUNT</b> вернет Вам число слов в
|
||
командной строке плюс один.
|
||
|
||
Альтернативный обработчик командной строки включается директивой
|
||
<b>?argc TRUE</b> или из командной строки компилятора ключом <b>/argc</b> или
|
||
строчкой <b>argc</b> в файле C--.INI.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.4>
|
||
2.1.4 /OST - слияние одинаковых строковых констант.
|
||
</h2>
|
||
|
||
Если этот режим оптимизации будет активизирован, то компилятор будет
|
||
запоминать все строковые константы и при обнаружении одинаковых в код
|
||
файла не будет вставлена повторная строковая константа, а будет сделана
|
||
ссылка на первую, обнаруженную ранее строковую константу. В оптимизации
|
||
участвуют только неименованные строковые константы. Т.е. если массив или
|
||
структура будет инициализированы строкой, то такая строка не будет
|
||
участвовать в процессе инициализации, так эта строка может быть изменена
|
||
в процессе работы программы. Пример:
|
||
|
||
char var="test"; //эта строка не будет участвовать в процессе
|
||
//оптимизации.
|
||
|
||
void proc(){
|
||
WRITESTR("test"); // эта строка будет участвовать в оптимизации.
|
||
AX="test"; // переменной AX будет присвоен адрес строки,
|
||
// которая была вставлена в код программы в
|
||
// предыдущей строке.
|
||
}
|
||
|
||
Обо всех случаях обнаружения повторной строки компилятор будет
|
||
выдавать предупреждения.
|
||
|
||
Включается этот режим оптимизации либо с командной строки <b>/ost</b>, либо
|
||
директивой <b>#pragma option ost</b>, либо строкой в файле c--.ini - <b>ost</b>.
|
||
Отключить, включенный ранее, этот режим можно директивой <b>#pragma option ost-</b>.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.5>
|
||
2.1.5 /D - установка идентификатора в TRUE из командной строки.
|
||
</h2>
|
||
|
||
Если Вы написали программу, которая может компилироваться по разному,
|
||
в зависимости от состояния некоторых идентификаторов (используется режим
|
||
условной компиляции), то Вам очень может пригодится эта опция.
|
||
Устанавливая с командной строки различные идентификаторы, Вы можете
|
||
получать различные варианты программы, не редактируя исходный текст
|
||
программы.
|
||
|
||
Идентификатор вводится с командной строки ключом <b>/d=idname</b>.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.6>
|
||
2.1.6 /IA - упрощенный ввод ассемблерных инструкций.
|
||
</h2>
|
||
|
||
Стало возможным использовать ассемблерные инструкции без префикса <b>$</b>
|
||
и вне блока <b>asm</b>. Этот режим включается: с командной строки опцией <b>/ia</b>;
|
||
в файле конфигурации строкой <b>ia</b> или директивой <b>#pragma option ia</b>.
|
||
|
||
Когда этот режим включен, все имена ассемблерных инструкций становятся
|
||
зарезервированными словами, т.е. Вы не сможете эти имена использовать в
|
||
качестве имен переменных или процедур. Ассемблерные инструкции компилятор
|
||
распознает независимо от того, написаны они маленькими или большими
|
||
буквами.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.7>
|
||
2.1.7 /CRI - пропуск повторно включаемого файла.
|
||
</h2>
|
||
|
||
Чаще всего, повторно включать файл в компилируемый проект, нет
|
||
необходимости, но это иногда происходит из-за того, что некоторые
|
||
включаемые файлы сами включают другие файлы. Чтобы этого не происходило
|
||
приходится делать проверку на повторную загрузку файла. Теперь эту
|
||
функцию берет на себя компилятор и у Вас отпадает необходимость делать
|
||
эту проверку.
|
||
|
||
Но иногда (очень редко) возникает потребность сделать повторное
|
||
включение файла. Для этого в компиляторе есть опция командной строки
|
||
<b>/cri-</b>, которая запрещает компилятору делать проверку на повторное
|
||
включение. Соответственно, для c--.ini файла, это можно сделать строкой
|
||
<b>cri-</b> или директивой в компилируемом файле - <b>#pragma option cri-</b>.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.8>
|
||
2.1.8 /IND - импорт имен процедур из DLL.
|
||
</h2>
|
||
|
||
Если Вы хотите в своей программе использовать DLL, для которой нет
|
||
заголовочного файла с описанием процедур, то компилятор может
|
||
импортировать имена из этой DLL. Для этого Вам надо указать имя этой
|
||
библиотеки либо через опцию командной строки <b>/ind=name.dll</b>, либо в
|
||
файле INI строкой 'ind=name.dll', либо через директиву '#pragma option
|
||
ind=name.dll'.
|
||
|
||
К недостатком такого способа получения имен можно отнести то, что при
|
||
компиляции программы библиотека, из которой импортируются имена,
|
||
обязательно должна присутствовать в компьютере. Также, если имена в
|
||
библиотеке написаны без суффикса '@number', компилятор не будет
|
||
контролировать число параметров передаваемых процедуре. И, к сожалению,
|
||
компилятор умеет импортировать имена из библиотек имеющих только формат
|
||
PE-файла.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.9>
|
||
2.1.9 /WS - задать имя stub файла для программ под windows.
|
||
</h2>
|
||
|
||
Как известно, в программах под windows есть DOS заглушка, называемая
|
||
stub, которой передается управление при запуске такой программы в чистом
|
||
DOS-е. Обычно такая заглушка выводит на экран сообщение о том, что эту
|
||
программу надо запускать в среде windows.
|
||
|
||
Вы можете вместо стандартного stub использовать свой. Для этого Вам
|
||
необходимо указать имя 16-битного EXE-файла либо через опцию командной
|
||
строки <b>/ws=filename</b>, либо строкой в INI-файле <b>ws=filename</b>, либо
|
||
директивой <b>#pragma option ws=filename</b>.
|
||
|
||
Таким образом, у Вас появилась возможность создавать программы,
|
||
работающие и под DOS и под windows.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.10>
|
||
2.1.10 /WBSS - разместить не инициализированные данные в отдельной секции.
|
||
</h2>
|
||
|
||
Секция <b>.bss</b> создается автоматически при компиляции программ с ключом
|
||
<b>/w32</b>. Если Вы хотите иметь эту секцию и при компиляции программ с
|
||
ключами <b>/w32c</b> или <b>/dll</b> Вам необходимо добавить либо в командной
|
||
строке опцию <b>/wbss</b>, либо строку <b>wbss</b> в INI-файле, либо директиву
|
||
<b>#pragma option wbss</b>.
|
||
|
||
Использование секции <b>.bss</b> практически не влияет на размер получаемого
|
||
файла. Теоретически, для процессоров, у которых есть отдельный кэш для
|
||
данных, использование секции <b>.bss</b>, должно повышать скорость работы
|
||
программы.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.11>
|
||
2.1.11 /DBG - создание отладочной информации.
|
||
</h2>
|
||
|
||
Если при компиляции программы в командную строку добавить ключ <b>/dbg</b>,
|
||
или в файл конфигурации c--.ini добавить строку <b>dbg</b>, то компилятор после
|
||
окончания компиляции создаст файл с отладочной информацией. Этот файл
|
||
имеет имя главного модуля и имеет расширение *.tds.
|
||
|
||
Отладочная информация создаваемая компилятором C-- совместима с
|
||
отладочной информацией создаваемой компиляторами фирмы Borland. Но, пока,
|
||
эта информация реализована еще не в полном объеме. Создаваемой сейчас
|
||
отладочной информации достаточно для проведения простейшей отладки
|
||
программы.
|
||
|
||
Для 16-битных программ под DOS для отладки надо использовать Turbo
|
||
Debugger из пакета Borland C v4.5 или лучше (файл td.exe).
|
||
|
||
Для программ под Windows надо использовать 32-битный отладчик из этого
|
||
же пакета (файл td32.exe).
|
||
|
||
Для 32-битных программ, использующих расширитель DOS применять для
|
||
отладки Turbo Debugger невозможно. Но, может быть я не знаю, как это
|
||
делать. Если Вы знаете, как создавать 32-битные программы с
|
||
DOS-расширителем компиляторами фирмы Borland с включением в них отладочной
|
||
информации, то расскажите мне. А я попробую применить это для C--.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.12>
|
||
2.1.12 /J0 /J1 /J2
|
||
</h2>
|
||
|
||
Синонимом ключей <b>/J0 /J1 /J2</b> является директива <b>#jumptomain</b> с
|
||
параметрами <b>NONE, SHORT и NEAR</b> соответственно.
|
||
|
||
Директива <b>#jumptomain</b> выполняет немного различные функции в
|
||
зависимости от типа выходного файла.
|
||
|
||
Компиляция файла типа <b>*.com</b> и <b>*.exe</b> модель памяти <b>tiny</b>:
|
||
|
||
<b>#jumptomain NONE (-j0)</b> - в этом случае по окончании кода начальной
|
||
инициализации программы не генерируется jmp на процедуру main. Эту
|
||
директиву следует использовать в случае, если до процедуры main нет других
|
||
не динамических процедур и инициализированных переменных.
|
||
|
||
<b>#jumptomain SHORT (-j1)</b> - в этом случае по окончании кода начальной
|
||
инициализации генерируется короткий jmp на процедуру main. Эту директиву
|
||
следует использовать, если до процедуры main находится не более 128 байт
|
||
кода и данных.
|
||
|
||
<b>#jumptomain NEAR (-j2)</b> - это состояние устанавливается по умолчанию. При
|
||
этом генерируется близкий jmp на процедуру main.
|
||
|
||
Компиляция файлов <b>*.exe</b> (ключи <b>-exe -d32 -w32 -w32c</b>):
|
||
|
||
<b>#jumptomain NONE (-j0)</b> - в этом случае код начальной инициализации
|
||
программы не генерируется и управление при запуске передается сразу на
|
||
процедуру main.
|
||
|
||
Во всех остальных случаях генерируется код начальной инициализации и
|
||
управление на процедуру main передается инструкцией call.
|
||
|
||
Компиляция файлов <b>*.dll</b>:
|
||
|
||
<b>#jumptomain NONE (-j0)</b> - в этом случае код начальной инициализации
|
||
программы не генерируется и управление при запуске передается сразу на
|
||
процедуру <b>main</b>.
|
||
|
||
Во всех остальных случаях генерируется код заглушки и управление на
|
||
процедуру <b>main</b> не передается. Фактически процедура <b>main</b> в этом случае не
|
||
нужна.
|
||
|
||
Процедура <b>main</b> при создании файлов <b>DLL</b> должна выглядеть немного иначе,
|
||
чем в других случаях:
|
||
|
||
dword main ( dword hInstDLL, reason, reserv )
|
||
{
|
||
...
|
||
}
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.13>
|
||
2.1.13 /LST - Создание ассемблерного листинга.
|
||
</h2>
|
||
|
||
С помощью дополнительной опции командной строки <b>-lst</b> Вы можете
|
||
получить вместе с исполнительным файлом и его ассемблерный листинг.
|
||
Листинг будет помещен в файл одноименный с исполнительным файлом и
|
||
имеющим расширение *.lst.
|
||
|
||
Ассемблерный листинг создается независимой от компилятора частью кода
|
||
с использованием информации накапливаемой при компиляции программы.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.14>
|
||
2.1.14 /ENV - Сохранение адреса переменных окружения.
|
||
</h2>
|
||
|
||
Если при компиляции программы Вы в командную строку добавите опцию
|
||
<b>-ENV</b> или в файл c--.ini строка <b>ENV</b>, то компилятор добавит в вашу
|
||
программу переменную <b>environ</b>, в которой при загрузке будет сохранятся
|
||
адрес переменных окружения запускаемой программы. Для программ под
|
||
Windows это будет полный адрес, а для остальных в этой переменной будет
|
||
сохраняться только адрес сегмента.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.15>
|
||
2.1.15 /CPA - Очистка post-области данных.
|
||
</h2>
|
||
|
||
Переменные, которым в теле программы не было присвоено никакое
|
||
значение, не включаются в тело скомпилированной программы. Для них
|
||
резервируется память за пределами программы. Но эта память может быть
|
||
заполнена произвольной информацией.
|
||
|
||
Если Вам необходимо, чтобы неинициализированные переменные при
|
||
загрузке программы всегда содержали одно и тоже значение (ноль) -
|
||
включите в командную строку опцию <b>-CPA</b>.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.16>
|
||
2.1.16 /W - вывод предупреждений.
|
||
</h2>
|
||
|
||
По умолчанию компилятор не выводит предупреждения и многие даже не
|
||
подозревают о существовании такой полезной опции. В C-- предупреждения
|
||
фактически являются подсказками для создания оптимальных программ и
|
||
зачастую облегчают отладку программ. В предупреждениях компилятор может
|
||
сообщить Вам о том, в каком месте можно использовать короткие формы
|
||
операторов IF, WHILE, FOR... О том, какие процедуры, переменные и
|
||
структуры определенные в вашей программе не были использованы. О том
|
||
какие регистры компилятор использовал без вашего ведома и много другой
|
||
полезной информации.
|
||
|
||
По умолчанию предупреждения выводятся на экран. Но их бывает так
|
||
много, что они могут не поместиться на экране. Поэтому в компиляторе есть
|
||
опция, по которой все предупреждения выводятся в файл. Имя этого файла
|
||
задается в той же опции. Поместив в свой c--.ini файл пару вот этих строк:
|
||
|
||
w
|
||
wf=warning
|
||
|
||
Вы будете получать в файле <b>warning</b> предупреждения.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.17>
|
||
2.1.17 /NW - Выборочное отключение типов предупреждений.
|
||
</h2>
|
||
|
||
Сейчас компилятор может выдавать 12 типов предупреждений и, иногда их
|
||
бывает так много, что становится трудно в них ориентироваться. Теперь
|
||
можно выборочно запрещать выдачу предупреждений. Для этого в командной
|
||
строке (или в файле C--.INI) можно установить опцию <b>/nw=number</b>, где
|
||
number - число от 1 до 12. Этим цифрам соответствуют следующие типы
|
||
предупреждений:
|
||
|
||
1 - Optimize numerical expressions
|
||
2 - Compiler used register ..."
|
||
3 - Short operator '...' may be used
|
||
4 - String '...' repeated
|
||
5 - Expansion variable
|
||
6 - Signed value returned
|
||
7 - '...' defined above, therefore skipped.
|
||
8 - Variable/structure/procedure '...' possible not used
|
||
9 - Non-initialized variable may have been used
|
||
10 - Return flag was destroyed
|
||
11 - Code may not be executable
|
||
12 - Don't use local/parametric values in inline procedures
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.1.18>
|
||
2.1.18 /WSI - короткая таблица импорта.
|
||
</h2>
|
||
|
||
Таблица импорта обычно состоит в свою очередь из четырех таблиц. Две
|
||
таблицы <b>LookUp Table</b> и <b>Import Address Table</b> абсолютно одинаковы.
|
||
|
||
Опцией командной строки <b>/WSI</b> Вы можете заставить компилятор
|
||
генерировать только одну из этих двух одинаковых таблиц (генерируется
|
||
только <b>Import Address Table</b>). Тем самым у Вас получится более компактная
|
||
таблица импорта, что приведет, в некоторых случаях, к созданию более
|
||
компактного выходного файла.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2>
|
||
2.2 Директивы транслятора.
|
||
</h2>
|
||
|
||
C-- не содержит препроцессор. Тем не менее, есть несколько функций
|
||
очень похожих на функции C препроцессора.
|
||
|
||
Они даются как директивы транслятора. Все директивы транслятора
|
||
начинаются с вопросительного знака <b>?</b> либо с символа <b>#</b>. Вот список имеющихся
|
||
директив и их назначение:
|
||
|
||
<b>? align</b> [val] Выровнять данные программы на четный по
|
||
умолчанию или на адрес кратный величине val.
|
||
|
||
<b>? aligncode</b> [val] Выровнять код программы на четный по
|
||
умолчанию или на адрес кратный величине <b>val</b>.
|
||
Заполнение производится кодом 0x90.
|
||
|
||
<b>? aligner</b> (aligner value) определить значение байта вставки.
|
||
|
||
<b>? alignword</b> (TRUE or FALSE) разрешает или запрещает выравнивание на
|
||
четный адрес переменных типа word и int,
|
||
значение по умолчанию TRUE.
|
||
|
||
<b>? argc</b> (TRUE or FALSE) Включить или отключить альтернативный
|
||
обработчик командной строки.
|
||
|
||
<b>? atexit</b> Вставляет в startup код поддержки процедуры
|
||
ATEXIT().
|
||
|
||
<b>? code32</b> (TRUE/FALSE) разрешает/запрещает генерацию 32-битного
|
||
кода.
|
||
|
||
<b>? codesize</b> оптимизация размера кода (в ущерб скорости).
|
||
|
||
<b>? compilerversion</b> min-vers указывает, компилятор какой версии необходим
|
||
для компиляции данной программы.
|
||
|
||
<b>? ctrl_c</b> (TRUE or FALSE ) разрешает или запрещает игнорирование
|
||
нажатия CTRL-C.
|
||
|
||
<b>? dataseg</b> (value) указывает компилятору сегментный адрес ОЗУ
|
||
для переменных при компиляции ROM-BIOS.
|
||
|
||
<b>? define</b> (identifier) (token) определяет идентификатор.
|
||
|
||
<b>? DOSrequired</b> (номер) устанавливает минимальную требуемую версию
|
||
DOS: старший байт - номер версии,
|
||
младший байт - номер модификации:
|
||
0x0101 для версии 1.1 DOS
|
||
0x0315 для версии 3.21 DOS
|
||
0x0303 для версии 3.3 DOS
|
||
0x0600 для версии 6.0 DOS
|
||
0x0602 для версии 6.2 DOS и т.д.
|
||
|
||
<b>? dosstring</b> (TRUE/FALSE) указывает компилятору, что в качестве
|
||
терминатора строки надо использовать символ <b>$</b>
|
||
|
||
<b>? else</b> генерирует альтернативный код если <b>?ifdef</b> или
|
||
<b>?ifndef</b> принимают значение FALSE (пример
|
||
использования смотрите в файле FPU.H--)
|
||
|
||
<b>? endif</b> указывает на конец действия директив <b>ifdef</b> и
|
||
<b>ifndef</b>
|
||
|
||
<b>? fastcallapi</b> (FALSE/TRUE) запретить/разрешить генерацию быстрого вызова
|
||
API-процедур (по умолчанию разрешено).
|
||
Директива работает при компиляции программ
|
||
под Windows.
|
||
|
||
<b>? fixuptable</b> (TRUE/FALSE) разрешить/запретить создание FixUp таблицы
|
||
(по умолчанию запрещено). Директива работает
|
||
при компиляции программ под Windows.
|
||
|
||
<b>? ifdef</b> (identifier) если идентификатор определен, то возвращает
|
||
TRUE иначе FALSE
|
||
|
||
<b>? imagebase</b> value задает адрес Image Base. По умолчанию этот
|
||
адрес равен 0x400000. Директива работает при
|
||
компиляции программ под Windows.
|
||
|
||
<b>? ifndef</b> (identifier) если идентификатор определен, то возвращает
|
||
FALSE иначе TRUE
|
||
|
||
<b>? include</b> ("filename") включает другой файл.
|
||
|
||
<b>? includepath</b> ("path") указание компилятору, в какой директории надо
|
||
искать включаемые файлы
|
||
|
||
<b>? initallvar</b> инициализирует 0 все неинициализированные
|
||
переменные.
|
||
|
||
<b>? jumptomain</b> (NONE, SHORT, NEAR or FALSE)
|
||
устанавливает тип перехода к main(),
|
||
значение по умолчанию - NEAR.
|
||
|
||
<b>? maxerrors</b> (number) максимальное количество найденных ошибок,
|
||
превысив которое транслятор прекращает
|
||
работу, значение по умолчанию - 16.
|
||
|
||
<b>? movedatarom</b> (TRUE/FALSE) указывает компилятору о необходимости
|
||
переноса данных из ПЗУ в ОЗУ.
|
||
|
||
<b>? parsecommandline</b> (TRUE or FALSE)
|
||
включает в программу блок кода для
|
||
синтаксического анализа командной строки
|
||
значение по умолчанию FALSE.
|
||
|
||
<b>? pragma</b> может объявлять несколько других директив
|
||
|
||
<b>? print</b> (number or string) выводит на экран строку или число.
|
||
|
||
<b>? printhex</b> (number) выводит на экран число в шестнадцатеричном
|
||
коде.
|
||
|
||
<b>? randombyte</b> вставляет в код программы байт случайного
|
||
значения.
|
||
|
||
<b>? resize</b> (TRUE or FALSE) включает функцию изменения после запуска
|
||
размера выделенного программе блока памяти
|
||
на минимально требуемый объем,
|
||
значение по умолчанию TRUE.
|
||
|
||
<b>? resizemessage</b> (string) сообщение, выводимое на экран перед
|
||
аварийным прерыванием выполнения программы,
|
||
если изменение размера выделенного программе
|
||
блока памяти не выполнено.
|
||
|
||
<b>? setdinproc</b> по этой директиве компилятор немедленно
|
||
вставляет в код компилируемой программы все
|
||
вызывавшиеся ранее динамические процедуры.
|
||
|
||
<b>? sizerom</b> (value) указывает компилятору размер ПЗУ.
|
||
|
||
<b>? speed</b> оптимизация быстродействия (значение
|
||
по умолчанию) в ущерб размеру кода.
|
||
|
||
<b>? stack</b> (number) определяет размер стека программы в байтах.
|
||
|
||
<b>? startaddress</b> (number) устанавливает стартовый адрес начала кода,
|
||
значение по умолчанию 0x100.
|
||
|
||
<b>? startuptomain</b> в com-файлах размещает <b>startup-</b>код в
|
||
процедуре <b>main()</b>.
|
||
|
||
<b>? startusevar</b> (number) указывает адрес, с которого разрешено
|
||
использовать ячейки памяти под
|
||
неинициализированные переменные.
|
||
|
||
<b>? sysattribute</b> (значение) эта директива передает компилятору атрибут
|
||
создаваемого драйвера. По умолчанию
|
||
устанавливается значение 0x2000.
|
||
Действует только с ключом <b>/SYS</b>.
|
||
|
||
<b>? sysname</b> <текстовая строка> эта директива передает компилятору имя
|
||
будущего драйвера. По умолчанию
|
||
присваивается имя <b>NO_NAME</b>. Длина имени не
|
||
более 8 символов. Действует только с ключом
|
||
<b>/SYS</b>.
|
||
|
||
<b>? syscommand</b> <command_0>,<command_1>, ...<command_n>; - эта директива
|
||
является обязательной при создании
|
||
драйверов. По этой директиве компилятору
|
||
передается список имен процедур обработки
|
||
команд драйвера. Действует только с ключом
|
||
<b>/SYS</b>.
|
||
|
||
<b>? warning</b> (TRUE or FALSE) эта директива разрешает или запрещает выдачу
|
||
предупреждений. Директива действует только в
|
||
пределах текущего файла и не влияет на
|
||
включаемые файлы.
|
||
|
||
<b>? winmonoblock</b> FALSE запрещает размещение таблиц файла формата PE
|
||
в одну секцию.
|
||
|
||
<b>? undef</b> уничтожает константы объявленные директивой
|
||
<b>? define</b>
|
||
|
||
<b>? use8086</b> ограничивается при генерации объектного кода
|
||
командами 8088/8086 (значение по умолчанию).
|
||
|
||
<b>? use8088</b> ограничивается при генерации объектного кода
|
||
командами 8088/8086 (значение по умолчанию).
|
||
|
||
<b>? use80186</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора 80186.
|
||
|
||
<b>? use80286</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора 80286.
|
||
|
||
<b>? use80386</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора 80386.
|
||
|
||
<b>? use80486</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора 80486.
|
||
|
||
<b>? usePentium</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора Pentium.
|
||
|
||
<b>? useMMX</b> допускает при генерации объектного кода
|
||
команды и оптимизацию для процессора Pentium
|
||
MMX.
|
||
|
||
<b>? usestartup</b> разрешает компилятору использовать ячейки
|
||
памяти, занимаемые кодом начальной
|
||
инициализации программы.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.1>
|
||
2.2.1 ?ifdef/?ifndef
|
||
</h2>
|
||
|
||
Ранее директива <b>?ifdef</b> срабатывала на наличие константы независимо
|
||
от значения ее величины, а директива <b>?ifndef</b> срабатывала на отсутствие
|
||
константы в компилируемом файле. Теперь <b>?indef</b> срабатывает лишь на
|
||
константу отличную от FALSE, а <b>?ifndef</b> срабатывает как на отсутствие
|
||
константы в компилируемом файле, так и на константу имеющую значение
|
||
FALSE.
|
||
|
||
Для директив <b>?ifdef/?ifndef</b> зарезервированы константы <i>codesize</i> и
|
||
<i>speed</i>, которые принимают значение TRUE или FALSE в зависимости от режима
|
||
оптимизации. Это будет полезным для создания более гибких библиотек.
|
||
|
||
Есть возможность проверки типа CPU для которого ведется компиляция.
|
||
Допустимые варианты синтаксиса:
|
||
|
||
?ifdef cpu > 1 //если программа компилируется для CPU выше 80186
|
||
?ifndef cpu >= 2 // -------//------------- не больше или равно 80286
|
||
?ifdef cpu == 3 // -------//------------- равно 80386
|
||
?ifdef cpu != 0 // -------//------------- не равен 8086
|
||
?ifdef cpu < 3 // -------//------------- хуже 80386
|
||
?ifdef cpu <= 2 // -------//------------- хуже или равен 80286
|
||
|
||
Эта директива позволит Вам писать одну процедуру для различных типов
|
||
CPU.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.2>
|
||
2.2.2 ?initallvar
|
||
</h2>
|
||
|
||
Директивой <b>?initallvar TRUE</b> включается режим при котором всем
|
||
неинициализированным переменным будет присвоено нулевое значение и они
|
||
будут располагаться в том месте, где были объявлены. Т.е. практически
|
||
исчезнут неинициализированные переменные. Это может быть полезным при
|
||
написании драйверов и резидентных программ.
|
||
|
||
Параметр FALSE этой директивы отключает этот режим.
|
||
По умолчанию эта директива установлена в FALSE.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.3>
|
||
2.2.3 ?usestartup
|
||
</h2>
|
||
|
||
Директива <b>?usestartup</b> разрешает компилятору использовать ячейки кода
|
||
начальной инициализации программы (startup) для последующего размещения в
|
||
них неинициализированных переменных. Это может быть полезным для получения
|
||
более компактного кода, как обычных программ, так и в особенности
|
||
резидентных.
|
||
|
||
Эту директиву применяют только для генерации *.COM файлов.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.4>
|
||
2.2.4 ?startusevar
|
||
</h2>
|
||
|
||
Директивой <b>?startusevar</b> можно указать начальный адрес с которого
|
||
компилятор будет распределять память для неинициализированных переменных.
|
||
Например, получив директиву <b>?startusevar 0x53</b> компилятор будет
|
||
располагать неинициализированные переменные, начиная с адреса 0x53. Это
|
||
может быть полезным для получения более компактного кода как для
|
||
резидентных, так и для обычных программ.
|
||
|
||
Эту директиву применяют только для генерации *.COM файлов.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.5>
|
||
2.2.5 ?atexit
|
||
</h2>
|
||
|
||
Директива <b>?atexit</b> добавляет в startup программы код поддержки
|
||
процедуры <b>ATEXIT</b>, резервирует место для хранения 16 адресов процедур и
|
||
изменяет код процедур <b>ABORT</b> и <b>EXIT</b>.
|
||
|
||
Процедура <b>ATEXIT</b> регистрирует процедуру, адрес которой передается ей в
|
||
качестве параметра, как процедуру завершения программы. Эта процедура
|
||
будет вызвана в момент завершения программы процедурами <b>ABORT</b> или <b>EXIT</b>
|
||
или инструкцией <b>RET</b> из <b>main</b>.
|
||
|
||
Всего можно зарегистрировать до 16 процедур. Процедуры вызываются в
|
||
порядке обратном порядку их регистрации.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.6>
|
||
2.2.6 ?startuptomain
|
||
</h2>
|
||
|
||
По этой директиве компилятор в начале файла делает <b>jmp</b> на начало
|
||
процедуры main(). Перед началом компиляции этой процедуры компилятор
|
||
начнет компиляцию startup кода и лишь затем будет продолжена компиляция
|
||
процедуры main(). Тем самым <b>startup код</b> окажется не в начале файла, как
|
||
это происходит обычно, а в теле процедуры main(). Это будет полезным при
|
||
компиляции резидентных программ (TSR).
|
||
|
||
Директива ?startuptomain работает только при компиляции com-файлов.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.7>
|
||
2.2.7 ?undef
|
||
</h2>
|
||
|
||
Эта директива уничтожает константы объявленные директивой <b>?define</b>. Ее
|
||
можно применять для изменения в процессе компиляции значения какой-нибудь
|
||
константы.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.8>
|
||
2.2.8 ?align и ?aligncode
|
||
</h2>
|
||
|
||
В C-- существует директива <b>?align</b>, которая делает однократное
|
||
выравнивание данных на четный адрес. Но если к этой директиве добавить
|
||
число, то выравнивание будет произведено на адрес кратный этому числу.
|
||
Например директива <b>?align 4</b> дополнит сегмент данных до адреса кратного
|
||
4. При выравнивании будут вставляться байты, значения которых определяются
|
||
директивой <b>?aligner</b>, по умолчанию это значение равно нулю. Директива
|
||
<b>?align</b> производит выравнивание только в сегменте данных. В тех моделях
|
||
памяти, в которых сегмент данных и кода совпадают эту директиву можно
|
||
применять и для выравнивания начала процедур.
|
||
|
||
Директива <b>?aligncode [value]</b> делает выравнивание в сегменте кода на
|
||
адрес кратный значению <b>value</b>, по умолчанию на четный адрес. Значение байта
|
||
заполнения в этой директиве является число 0x90 - код инструкции NOP.
|
||
Значение байта заполнения для этой директивы изменить нельзя. Т.о. эту
|
||
директиву можно применять и внутри исполняемого кода. Например, если Вы
|
||
хотите получить быстрый код на 486 процессоре, то рекомендуется делать
|
||
выравнивание начала процедур и циклов на адрес кратный 16.
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=2.2.9>
|
||
2.2.9 ?pragma
|
||
</h2>
|
||
|
||
Директива <b>#pragma</b> это многофункциональнальная директива, которая в
|
||
свою очередь имеет свои директивы:
|
||
|
||
<b>option</b>
|
||
Директива <b>option</b> позволяет включить в Ваш код опции командной строки
|
||
компилятора. Некоторые опции не могут быть использованы в этой директиве;
|
||
другие должны помещаться в самом начале исходного текста. Пример:
|
||
|
||
#pragma option w32c
|
||
|
||
Эта директива объявляет компилятору, что надо создать консольный
|
||
32-битный файл под windows.
|
||
|
||
<b>startup</b>
|
||
Директивой <b>startup</b> можно указать функцию, которая будет выполнена перед
|
||
запуском процедуры <b>main</b>. Эта директива имеет такой формат:
|
||
|
||
#pragma startup procname
|
||
|
||
Количество раз, которое можно применять эту директиву в одной
|
||
программе не ограничено, но реально можно использовать лишь несколько
|
||
тысяч раз.
|
||
|
||
<b>line</b>
|
||
Директива <b>line</b> выводит на экран номер текущей строки и имя файла.
|
||
Дополнительно может выводиться содержимое строки находящееся после слова
|
||
<b>line</b>. Пример:
|
||
|
||
#pragma line information
|
||
|
||
Встретив эту директиву, компилятор выведет на экран номер строки и имя
|
||
файла. Также будет выведено сообщение справа от слова <b>line</b>, если оно
|
||
есть.
|
||
|
||
<b>resource</b>
|
||
Эта директива может принимать значения <b>start</b> и <b>end</b>. Эти два
|
||
значения выделяют начало и конец блока ресурсов, если вы используете его
|
||
непосредственно в исходном коде файла, а не в отдельном файле. Пример:
|
||
|
||
#pragma resource start
|
||
|
||
MyMenu MENU DISCARDABLE
|
||
BEGIN POPUP "Files",HELP
|
||
BEGIN
|
||
MENUITEM "Open", ID_OPEN
|
||
MENUITEM "Save", ID_SAVE
|
||
MENUITEM SEPARATOR
|
||
MENUITEM "Exit", ID_EXIT
|
||
END
|
||
MENUITEM "Other", 65535
|
||
END
|
||
|
||
#pragma resource end
|
||
<a href="#contents2"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=3.1>
|
||
3. Константы.
|
||
|
||
3.1 Числовые константы.
|
||
</h2>
|
||
|
||
Представление числовых констант в виде десятичных чисел (чисел с
|
||
основанием 10) и шестнадцатеричных чисел (основание счисления 16) полностью
|
||
аналогично языку <b>C</b>.
|
||
|
||
При двоичном представлении чисел (основание 2) число должно начинаться
|
||
с символов <b>0b</b>, за которыми без пробела идет последовательность нулей и
|
||
единиц.
|
||
|
||
При восьмеричном представлении чисел (основание 8) число должно
|
||
начинаться с символов <b>0o</b>, за которыми без пробела идет последовательность
|
||
цифр.
|
||
|
||
Вещественное число отличается от целого по наличию в нем точки.
|
||
Начинаться вещественное число должно либо цифрой от 0 до 9, либо знаком
|
||
минус. Необязательной частью вещественного числа является показатель
|
||
степени. Показатель степени отделяется от числа символом <b>e</b> или <b>E</b>.
|
||
Пробелы недопустимы.
|
||
|
||
Примеры:
|
||
0b11111111 // двоичное представление числа 255
|
||
0x00F // шестнадцатеричное представление числа 15
|
||
0o10 // восьмеричное представление числа 8
|
||
1.234567E-20 // вещественное число
|
||
|
||
C-- вместе с традиционным <b>C-</b>стилем шестнадцатеричных чисел понимает и
|
||
числа записанные в стиле ассемблера. Для тех, кто вдруг не знает, сообщаю,
|
||
что шестнадцатеричные числа в ассемблере имеют на конце символ <b>h</b> или <b>H</b>.
|
||
Если первый символ шестнадцатеричного числа больше <b>9</b>, то перед ним
|
||
обязательно должен быть записан символ <b>0</b>. Примеры:
|
||
|
||
1234h
|
||
0A000H
|
||
|
||
К числовым константам можно писать суффиксы <b>L, U и F</b>. Фактически
|
||
эти суффиксы в C-- не играют никакой роли, компилятор их просто
|
||
проглатывает. Пример:
|
||
|
||
#define DEF 1L
|
||
#define DEF2 2Lu
|
||
#define DEF3 3.0F
|
||
|
||
Эти суффиксы не зависят от регистра, т.е. их можно писать как
|
||
маленькими, так и большими буквами.
|
||
<a href="#contents3"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=3.2>
|
||
3.2 Символьные константы.
|
||
</h2>
|
||
|
||
Одиночные символьные константы, как и в <b>C</b>, должны заключаться в
|
||
одиночные кавычки <b>'</b>.
|
||
|
||
Также как и в <b>C</b>, для обозначения специальных символов служит обратная
|
||
наклонная черта вправо <b>\</b> с последующим за ней ключевым символом (или
|
||
несколькими символами). Поддерживаются следующие специальные символы:
|
||
|
||
\a /* звуковой сигнал */
|
||
\b /* забой */
|
||
\f /* перевод страницы */
|
||
\l /* перевод строки */
|
||
\n /* возврат каретки*/
|
||
\r /* возврат каретки*/
|
||
\t /* табуляция */
|
||
\x?? /* символ ASCII, соответствующий байтовому представлению,
|
||
состоящему из двух шестнадцатеричных цифр, расположенных
|
||
на месте знаков вопроса */
|
||
\??? /* символ ASCII, соответствующий байтовому представлению,
|
||
состоящему из трех десятичных цифр, расположенных
|
||
на месте знаков вопроса */
|
||
|
||
Любой другой символ после обратной наклонной черты вправо будет принят
|
||
как простой символ.
|
||
|
||
Символ "Одиночная кавычка" <b>'</b> может быть введен при помощи конструкции
|
||
<b>\'</b>
|
||
|
||
Символ NULL может быть введен как ''
|
||
|
||
В C-- поддерживаются и многобуквенные символьные константы. Примеры
|
||
многобуквенных символьных констант:
|
||
|
||
'ab'
|
||
'the'
|
||
'this is large'
|
||
|
||
Никакого ограничения на число символов в символьной константе не
|
||
накладывается, но различаются только последние 4 символа. Это - максимум,
|
||
который может быть сохранен в 32-разрядной переменной. Например, константы
|
||
<b>this is large</b> и <b>arge</b> - одинаковы.
|
||
|
||
C-- обрабатывает все символьные константы как числовые значения ASCII
|
||
символов. Для многобуквенных символьных констант первый символ
|
||
соответствует старшим разрядам, таким образом, значение для <b>ab</b> будет
|
||
закодировано как <b>a*256+b</b>.
|
||
<a href="#contents3"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=3.3>
|
||
3.3 Строковые константы.
|
||
</h2>
|
||
|
||
Строковые константы, как и в C, заключаются в двойные кавычки (").
|
||
Специальные символы внутри строк обозначаются так же, как и в символьных
|
||
константах. Все специальные символы имеют то же значение, что и в
|
||
символьных константах за исключением <b>\n</b>, который имеет значение <b>новая
|
||
строка</b> и заменяет собой пару символов <b>возврат каретки</b> и <b>перевод
|
||
строки</b>.
|
||
|
||
В настоящее время наибольшая длина строковой константы - 2048 символов,
|
||
включая символ-ограничитель 0, таким образом, максимум 2047 значащих
|
||
символов.
|
||
<a href="#contents3"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=3.4>
|
||
3.4 Постоянные выражения.
|
||
</h2>
|
||
|
||
Постоянное выражение - одиночная числовая константа или несколько
|
||
числовых констант, связанных между собой операторами. Числовое значение
|
||
выражения вычисляется один раз во время компиляции и далее используется
|
||
только его постоянное значение.
|
||
|
||
Подобно всем выражениям в C--, постоянные выражения всегда вычисляются
|
||
слева направо, невзирая на правила арифметики! Это совершенно отлично от
|
||
других языков, и при написании выражений надо быть осторожным и помнить,
|
||
что 2+3*2=10 а не 8.
|
||
|
||
Некоторые примеры постоянных выражений:
|
||
45 & 1 + 3 // равняется 4
|
||
14 - 1 / 2 // равняется 6 (помните целочисленные значения)
|
||
1 * 2 * 3 / 2 + 4 // равняется 7
|
||
Примеры с применением вещественных чисел:
|
||
3.23*1.53+2.0E2 // равняется 204.9419
|
||
<a href="#contents3"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.1>
|
||
4. Выражения.
|
||
|
||
4.1 Типы выражений.
|
||
</h2>
|
||
|
||
Имеются три типа выражений в C--, не считая постоянных выражений. Это
|
||
выражения типа <b>EAX/AX/AL</b>, выражения типа <b>неEAX/AX/AL</b> и условные выражения.
|
||
Все C-- выражения вычисляются слева направо, независимо от старшинства
|
||
входящих в выражение математических операций.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.2>
|
||
4.2 Выражения типа EAX/AX/AL.
|
||
</h2>
|
||
|
||
Этот тип выражений применяется в случае, когда его результат может быть
|
||
сохранен в переменной в памяти или в регистре <b>EAX</b> или <b>AX</b> или <b>AL</b>.
|
||
|
||
Если результат может быть сохранен в переменных типа <b>byte</b> или <b>char</b>,
|
||
используется нотация <b>AL</b>.
|
||
|
||
Если результат может быть сохранен в переменных типа <b>word</b> или <b>int</b>,
|
||
используется нотация <b>AX</b>.
|
||
|
||
Если результат может быть сохранен в переменных типа <b>dword, long</b> или
|
||
<b>float</b>, используется нотация <b>EAX</b>.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.3>
|
||
4.3 Выражения использующие получатель при вычислении выражения.
|
||
</h2>
|
||
|
||
Если в правой части выражения используется переменная являющаяся
|
||
одновременно и приемником, то такие выражения дают различные результаты в
|
||
зависимости от того является приемник регистром или переменной памяти. Это
|
||
связано с тем, что при вычислении выражения в переменную памяти, вычисление
|
||
производится сначала в регистр <b>EAX/AX/AL</b>, и лишь после окончания вычисления
|
||
результат будет записан в приемник. Если же приемником является регистр, то
|
||
его значение будет меняться после каждой операции вычисления. Пример:
|
||
|
||
int var;
|
||
var = BX = 2;
|
||
var = 3 + var; // результатом будет 5
|
||
BX = 3 + BX; // результатом будет 6
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.4>
|
||
4.4 Не - EAX/AX/AL выражения.
|
||
</h2>
|
||
|
||
Этот тип выражений применяется в случае, когда его результат должен
|
||
быть сохранен в любом другом регистре, отличном от аккумулятора <b>EAX, AX</b>
|
||
или <b>AL</b>. В процессе вычисления выражения этого типа меняется только
|
||
содержимое указанного регистра-получателя, все другие регистры будут
|
||
сохранены. Если регистром-получателем служит байтовый регистр, а при
|
||
вычислении используются величины размером в слово, одновременно с записью в
|
||
младший байт может быть разрушено содержимое старшего байта
|
||
регистра-получателя.
|
||
|
||
Это обстоятельство накладывает некоторые ограничения на операции и
|
||
операнды, допустимые в выражениях типа <b>не EAX/AX/AL</b>. Внутри выражений
|
||
байтового типа не допускается:
|
||
|
||
- делать вызовы МАКРОКОМАНД,
|
||
- делать вызовы РЕГИСТРОВЫХ процедур
|
||
- делать вызовы СТЕКОВЫХ процедур
|
||
|
||
Ранее в <b>не-EAX/AX/AL</b> выражениях было можно использовать лишь
|
||
операции: сложения, вычитания, XOR, OR, AND. Теперь для 16 и 32 битных
|
||
регистров почти все ограничения сняты. Но есть еще ограничения на регистры.
|
||
Например, если в выражении используется сдвиг на значение переменной, а
|
||
приемником являются регистры <b>CX/ECX,</b> то такое выражение компилятор не будет
|
||
компилировать:
|
||
|
||
CX = var * SI * 3 * var >> 3; //вызовет сообщение об ошибке
|
||
|
||
Примечание: для 8 битных <b>не-AL</b> выражений умножать можно только на
|
||
числа: 0, 1, 2, 4, 8, 16, 32, 64 и 128. Все эти ограничения связаны со
|
||
стремлением не разрушать другие регистры при использовании <b>не-EAX/AX/AL</b>
|
||
выражений.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.5>
|
||
4.5 Условные выражения.
|
||
</h2>
|
||
|
||
Условные выражения - выражения, результатом вычисления которых является
|
||
логическое значение да или нет, используемое в операторе <b>if</b> и циклах <b>do {}</b>
|
||
<b>while, while, for</b>.
|
||
|
||
Имеются два типа условных выражений, простые и сложные.
|
||
|
||
Возможно логическое объединение условий.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.5.1>
|
||
4.5.1 Простые условные выражения.
|
||
</h2>
|
||
|
||
Простые условные выражения - одиночная лексема или выражение, которое
|
||
примет значение да, если расчетное значение отлично от нуля, или значение
|
||
нет, если расчетное значение равно нулю.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.5.2>
|
||
4.5.2 Сложные условные выражения.
|
||
</h2>
|
||
|
||
Сложные условные выражения имеют следующую форму:
|
||
|
||
(левая_часть оператор_отношения правая_часть)
|
||
|
||
Где:
|
||
левая_часть - любое выражение типа <b>AL/AX/EAX</b> или постоянное выражение.
|
||
Тип выражения определяется по типу первой лексемы
|
||
(регистра или переменной); значение типа по умолчанию -
|
||
word для 16-битных программ и dword для 32-битных. Если
|
||
желателен другой тип, перед выражением ставится
|
||
соответствующее ключевое слово, определяющее его тип:
|
||
<b>byte, char, int, long, dword</b> или <b>float</b>
|
||
|
||
оператор_отношения - любой из операторов отношения:
|
||
<b>==, !=, <>, <, >, <=, или >=</b>.
|
||
|
||
правая_часть - любой одиночный регистр, одиночная переменная или
|
||
постоянное выражение.
|
||
|
||
Примеры правильных сложных условных выражений:
|
||
|
||
(X + y > z)
|
||
(int CX*DX < = 12*3)
|
||
(byte first*second+hold == cnumber)
|
||
|
||
Примеры недопустимых сложных условных выражений:
|
||
|
||
(x+y >= x-y) // правая часть не является одиночной лексемой или
|
||
постоянным выражением.
|
||
(Z = y) // вместо == ошибочно поставлен =
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.6>
|
||
4.6 Изменение типа выражения при присваивании.
|
||
</h2>
|
||
|
||
Если после знака равенства написать тип отличный от типа вычисляемой
|
||
переменной, то все переменные участвующие в процессе вычисления, будут
|
||
преобразовываться к этому новому типу, и лишь конечный результат будет
|
||
преобразован к типу вычисляемой переменной. Пример:
|
||
|
||
int i, a;
|
||
long b;
|
||
char c;
|
||
|
||
i = a * b + c ;
|
||
|
||
Значения переменных a, b, и c в этом примере перед вычислением будут
|
||
преобразованы к типу <b>int</b> (типу переменной i). Но если записать это
|
||
выражение вот так:
|
||
|
||
i = long a * b + c ;
|
||
|
||
то переменные a, b, и c в этом примере перед вычислением будут
|
||
преобразованы к типу <b>long</b>, а конечный результат будет преобразован к типу
|
||
переменной i - <b>int</b>.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=4.7>
|
||
4.7 Вычисление в регистры EAX/AX/AL со знаком.
|
||
</h2>
|
||
|
||
По умолчанию все вычисления в регистры производятся как с без знаковыми
|
||
величинами.
|
||
|
||
Например:
|
||
|
||
int a,b,c;
|
||
AX = a * b / c ;
|
||
|
||
При этом компилятор генерировал без знаковые инструкции <b>div</b> и <b>mul</b>, так как
|
||
регистры считаются без знаковыми переменными. Если написать вот так:
|
||
|
||
AX = int a * b / c ;
|
||
|
||
то компилятор сгенерирует инструкции <b>idiv</b> и <b>imul</b>.
|
||
|
||
Обращаю ваше внимание, что для регистра <b>AL</b> можно использовать только
|
||
модификатор <b>char</b>, для <b>AX</b> соответственно только <b>int</b>, а для <b>EAX - long</b>. Для
|
||
остальных регистров подобное делать нельзя.
|
||
<a href="#contents4"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=5.1>
|
||
5. Идентификаторы.
|
||
|
||
5.1 Формат идентификатора.
|
||
</h2>
|
||
|
||
Идентификаторы в C-- должны начинаться или с символа подчеркивания <b>_</b>
|
||
или заглавных или строчных букв. Следующие символы могут быть любой
|
||
комбинацией символов подчеркивания, заглавных или строчных букв или чисел
|
||
(от 0 до 9). Общая длина идентификатора не может превышать 64 символа.
|
||
Символы с кодом больше 0x7A (код символа <b>z</b>) недопустимы.
|
||
|
||
Примеры допустимых идентификаторов:
|
||
|
||
_DOG
|
||
Loony12
|
||
HowdYBoys_AND_Girls
|
||
WOW___
|
||
X
|
||
|
||
Примеры недопустимых идентификаторов:
|
||
|
||
12bogus /* не может начинаться с числа */
|
||
WowisthisalongidentifieryupitsureisnotOyoulengthismorethat64chars
|
||
/*длина идентификатора превышает 64 */
|
||
Y_es sir /* пробелы недопустимы */
|
||
The-end /* дефисы недопустимы */
|
||
<a href="#contents5"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=5.2>
|
||
5.2 Зарезервированные идентификаторы.
|
||
</h2>
|
||
|
||
Список зарезервированных в C-- идентификаторов, которые не могут
|
||
использоваться как общие идентификаторы, поскольку они уже были определены
|
||
или зарезервированы для других целей:
|
||
|
||
<b>BREAK CASE CONTINUE ELSE EXTRACT FALSE FOR
|
||
FROM GOTO IF LOOPNZ RETURN SWITCH TRUE
|
||
WHILE
|
||
|
||
CARRYFLAG MINUSFLAG NOTCARRYFLAG NOTOVERFLOW
|
||
NOTZEROFLAG OVERFLOW PLUSFLAG ZEROFLAG
|
||
|
||
__CODEPTR__ __COMPILER__ __DATAPTR__ __DATESTR__ __DATE__ __DAY__
|
||
__HOUR__ __LINE__ __MINUTE__ __MONTH__ __POSTPTR__ __SECOND__
|
||
__TIME__ __VER1__ __VER2__ __WEEKDAY__ __YEAR__
|
||
|
||
_export asm break byte case cdecl char continue
|
||
default do dword else enum extern far fastcall
|
||
float for goto if inline int interrupt long
|
||
loop loopnz pascal return short signed sizeof static
|
||
stdcall struct switch union unsigned void while word
|
||
|
||
ESCHAR ESBYTE ESINT ESWORD ESLONG ESDWORD ESFLOAT
|
||
CSCHAR CSBYTE CSINT CSWORD CSLONG CSDWORD CSFLOAT
|
||
SSCHAR SSBYTE SSINT SSWORD SSLONG SSDWORD SSFLOAT
|
||
DSCHAR DSBYTE DSINT DSWORD DSLONG DSDWORD DSFLOAT
|
||
FSCHAR FSBYTE FSINT FSWORD FSLONG FSDWORD FSFLOAT
|
||
GSCHAR GSBYTE GSINT GSWORD GSLONG GSDWORD GSFLOAT
|
||
|
||
AX CX DX BX SP BP SI DI
|
||
EAX ECX EDX EBX ESP EBP ESI EDI
|
||
AL CL DL BL AH CH DH BH
|
||
ES CS SS DS FS GS
|
||
|
||
ST(0) ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7) ST
|
||
st(0) st(1) st(2) st(3) st(4) st(5) st(6) st(7) st
|
||
</b>
|
||
Этот список может быть получен из C-- транслятора в любое время,
|
||
запуском его с опцией <b>/WORDS</b> из командной строки.
|
||
|
||
Если Вы пользуетесь при компиляции опцией командной строки <b>/ia</b>, которая
|
||
позволяет использовать ассемблерные инструкции не заключая их в блоки <b>asm</b> и
|
||
без префикса <b>$</b>, то все имена ассемблерных инструкций становятся
|
||
зарезервированными словами. Причем имена ассемблерных инструкций компилятор
|
||
различает независимо от того, написаны они маленькими или большими буквами.
|
||
|
||
Список имен поддерживаемых компилятором ассемблерных инструкции можно
|
||
получить запустив компилятор с опцией <b>/LAI</b>.
|
||
|
||
Кроме этого в ассемблерных инструкциях становятся зарезервированными
|
||
следующие идентификаторы:
|
||
|
||
<b>ax cx dx bx sp bp si di
|
||
eax ecx edx ebx esp ebp esi edi
|
||
al cl dl bl ah ch dh bh
|
||
es cs ss ds fs gs
|
||
|
||
DR0 DR1 DR2 DR3 DR4 DR5 DR6 DR7
|
||
CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7
|
||
TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7
|
||
MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7
|
||
XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
|
||
|
||
dr0 dr1 dr2 dr3 dr4 dr5 dr6 dr7
|
||
cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7
|
||
tr0 tr1 tr2 tr3 tr4 tr5 tr6 tr7
|
||
mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7
|
||
xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7
|
||
</b><a href="#contents5"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=5.3>
|
||
5.3 Универсальные регистры для 16 и 32-битного режима.
|
||
</h2>
|
||
|
||
При создании библиотечных процедур очень часто приходится писать
|
||
варианты процедуры для работы в 16-битном и 32-битном режимах, которые
|
||
отличаются друг от друга лишь использованием в них либо 16-битных либо
|
||
32-битных регистров соответственно. Но можно писать лишь одну процедуру,
|
||
используя в ней новый синтаксис регистров. Если компилятор встретит вот
|
||
такой синтаксис:
|
||
|
||
(E)AX=0;
|
||
|
||
то компилятор будет использовать при компиляции 16-битного кода регистр
|
||
<b>AX</b>, а при компиляции 32-битного кода регистр <b>EAX</b>.
|
||
|
||
Использование автоматических регистров позволит упростить библиотечные
|
||
файлы и сделать их более понятными.
|
||
<a href="#contents5"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=5.4>
|
||
5.4 Предопределенные идентификаторы.
|
||
</h2>
|
||
|
||
Идентификаторы, определяемые компилятором в зависимости от режима
|
||
компиляции:
|
||
|
||
<b>__TLS__</b> идет компиляция под windows (w32, w32c, dll).
|
||
<b>__DLL__</b> идет компиляция dll.
|
||
<b>__CONSOLE__</b> идет компиляция консольного приложения windows
|
||
<b>__WIN32__</b> идет компиляция GUI-шного приложения
|
||
<b>__FLAT__</b> компилируется 32-битный код.
|
||
<b>__MSDOS__</b> компилируется 16-битный код.
|
||
<b>__TINY__</b> используется модель памяти tiny в 16-битном режиме
|
||
<b>__SMALL__</b> используется модель памяти small в 16-битном режиме
|
||
<b>__DOS32__</b> компилируется 32-битный код под DOS (d32)
|
||
<b>__COM__</b> компилируется com-файл
|
||
<b>__SYS__</b> компилируется sys-файл
|
||
<b>__ROM__</b> компилируется rom-файл
|
||
<b>__OBJ__</b> компилируется obj-файл
|
||
<b>__TEXE__</b> компилируется exe-файл модели tiny
|
||
<b>__EXE__</b> компилируется exe-файл модели small
|
||
<b>__MEOS__</b> компилируется исполняемый файл для MenuetOS
|
||
<b>codesize</b> компиляция ведется с оптимизацией на размер кода
|
||
<b>speed</b> компиляция ведется с оптимизацией на быстродействие кода
|
||
<b>cpu</b> определяет тип процессора для которого ведется компиляция:
|
||
0 - 8086
|
||
1 - 80186
|
||
2 - 80286
|
||
3 - 80386
|
||
4 - 80486
|
||
5 - Pentium
|
||
6 - Pentium MMX
|
||
7 - Pentium II
|
||
|
||
Эти идентификаторы могут быть проверены директивами <b>#ifdef</b> или <b>#ifndef</b>.
|
||
Идентификатор <b>cpu</b> может быть использован лишь с операторами проверки
|
||
условий:
|
||
|
||
#ifdef cpu > 3 //если тип процессора больше 80386
|
||
<a href="#contents5"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.1>
|
||
6. Переменные.
|
||
|
||
6.1 Типы переменных.
|
||
</h2>
|
||
|
||
В C-- имеется семь типов переменных (именованных областей памяти), это:
|
||
<b>byte, word, dword, char, int, long, float.</b>
|
||
|
||
Следующая таблица показывает размер и диапазон представляемых величин
|
||
каждого из типов переменной:
|
||
|
||
NAME | SIZE | VALUE RANGE | VALUE RANGE
|
||
тип |размер | диапазон представления | диапазон представления
|
||
|в байт.| в десятичной системе | в шестнадцатеричной системе
|
||
---------------------------------------------------------------------------
|
||
byte | 1 | 0 to 255 | 0x00 to 0xFF
|
||
word | 2 | 0 to 65535 | 0x0000 to 0xFFFF
|
||
dword | 4 | 0 to 4294967295 | 0x00000000 to 0xFFFFFFFF
|
||
char | 1 | -128 to 127 | 0x80 to 0x7F
|
||
int | 2 | -32768 to 32767 | 0x8000 to 0x7FFF
|
||
long | 4 | -2147483648 to 2147483647 | 0x80000000 to 0x7FFFFFFF
|
||
float | 4 | -3,37E38 to +3,37E38 | 0xFF7FFFFF to 0x7FFFFFFF
|
||
|
||
Примечание: для работы с типами <b>float, dword и long</b> используются
|
||
32-разрядные целочисленные команды, следовательно, для их выполнения нужно
|
||
иметь процессор не хуже 80386, что сейчас не является большой проблемой.
|
||
|
||
Для совместимости со стандартом, принятом в языке <b>C</b>, введены
|
||
новые зарезервированные слова: <b>short</b>, <b>signed</b>, <b>unsigned</b>. Для типа <b>int</b>
|
||
в 32-битном режиме изменена разрядность. Вот таблица всех вариантов новых
|
||
типов данных:
|
||
|
||
---------------------------------------------------------
|
||
| полный тип |допустимые сокращения|старые аналоги|
|
||
---------------------------------------------------------
|
||
|signed char |char | char |
|
||
|signed int |signed, int | int/long |
|
||
|signed short int |short, signed short | int |
|
||
|signed long int |long, signed long | long |
|
||
|unsigned char |--- | byte |
|
||
|unsigned int |unsigned | word/dword |
|
||
|unsigned short int|unsigned short | word |
|
||
|unsigned long int |unsigned long | dword |
|
||
---------------------------------------------------------
|
||
|
||
Старые типы <b>byte, word и dword</b> поддерживаются по прежнему и имеют
|
||
функционально прежнее значение. Изменения коснулись лишь типа <b>int</b>. Он в
|
||
16-битном режиме, также как и тип <b>unsigned int</b>, имеет 16-битный размер, а
|
||
в 32-битном режиме эти оба типа имеют размер в 32-бита. На первый взгляд
|
||
такие свойства типа <b>int</b> вносят некоторую путаницу, но это дает большой
|
||
выигрыш при использовании этого типа в библиотечных файлах, которые могут
|
||
быть использованы при компиляции 16-битных и 32-битных программ.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.2>
|
||
6.2 Объявление переменных.
|
||
</h2>
|
||
|
||
Синтаксис для объявления переменных следующий:
|
||
|
||
variable-type identifier;
|
||
|
||
где <b>variable-type - char, byte, int, word, long, dword</b> или <b>float</b>.
|
||
|
||
Одновременно могут быть объявлены несколько идентификаторов одного типа:
|
||
|
||
variable-type identifier1, identifier2, ... , identifierN;
|
||
|
||
Одномерные массивы могут быть объявлены следующим образом:
|
||
|
||
variable-type identifier[elements];
|
||
|
||
где <b>elements</b> - постоянное выражение для количества переменных этого типа,
|
||
объединенных в массив.
|
||
|
||
Инициализированные массивы можно объявлять без указания числа
|
||
элементов. При этом будет создан массив по фактическому числу элементов.
|
||
|
||
variable-type identifier[] = { const1, const2 };
|
||
|
||
Переменные при объявлении могут быть проинициализированы следующим
|
||
образом:
|
||
|
||
variable-type identifier = value;
|
||
|
||
Некоторые примеры глобальных объявлений:
|
||
byte i,j; /* объявляет две переменные типа byte с именами i и j */
|
||
word see[10] /* объявляет массив с именем see, состоящий из 10
|
||
элементов типа word */
|
||
int h,x[27] /* объявляет, переменную типа int с именем h,
|
||
и массив с именем x, состоящий из 27 элементов типа int */
|
||
long size=0; /* объявлена переменная типа long с именем size и ей присвоено
|
||
значение 0. */
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.3>
|
||
6.3 Глобальные переменные.
|
||
</h2>
|
||
|
||
Глобальные переменные - это переменные, область действия которых
|
||
распространяется на всю программу. В C-- использовать глобальные переменные
|
||
можно в процедурах, расположенных ниже места ее объявления. Т.е. если Вы
|
||
пишите процедуру, в которой используете переменную var, а саму переменную
|
||
объявляете ниже текста процедуры, то компилятор выдаст ошибку. Это связано
|
||
с тем, что компилятор может знать тип переменной только после их
|
||
объявления. Но для таких переменных можно использовать взятие их адреса,
|
||
так как адрес переменной не зависит от его типа. Пример:
|
||
|
||
void Proc(){
|
||
gvar = 0; /* компилятор выдаст сообщение об ошибке, т.к. он еще не знает
|
||
типа переменной gvar */
|
||
AX = #gvar; /* несмотря на то, что компилятор не знает и адреса этой
|
||
переменной такое выражение будет откомпилировано */
|
||
}
|
||
int gvar;
|
||
|
||
Но все же ситуация не безнадежна и нам удастся добиться того, чего мы
|
||
задумали. В этом нам поможет альтернативный синтаксис обращения к
|
||
переменным:
|
||
|
||
void Proc(){
|
||
DSINT[#gvar] = 0; /* компилятор успешно откомпилирует это выражение т.к.
|
||
ему теперь известен тип переменной gvar */
|
||
}
|
||
int gvar;
|
||
|
||
Память под глобальные переменные выделяется в сегменте данных. Если
|
||
переменная при объявлении инициализируется (т.е. ей присвоено какое-то
|
||
значение), то переменная будет включена в код компилируемого файла. Если
|
||
переменная не инициализируется, то место для переменной будет
|
||
зарезервировано сразу же за последним байтом скомпилированной программы.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.4>
|
||
6.4 Локальные переменные.
|
||
</h2>
|
||
|
||
Локальные переменные - это переменные область действия которых
|
||
распространяется лишь в пределах одной процедуры. Объявлять локальные
|
||
переменные, в отличии от современных версий <b>C</b>, можно между именем процедуры
|
||
и первой открывающейся фигурной скобкой. Пример:
|
||
|
||
void PROC ()
|
||
int i; //объявлена локальная переменная типа int с именем i
|
||
{
|
||
for ( i=0; i<10; i++ ) WRITE(1);
|
||
}
|
||
|
||
Память под локальные переменные отводится в сегменте стека.
|
||
|
||
К локальным переменным можно отнести и параметры стековых процедур. Под
|
||
них также отводится память в стеке.
|
||
|
||
Можно инициализировать локальные переменные при их объявлении. Но есть
|
||
некоторые ограничения. Нельзя инициализировать массивы и многомерные
|
||
структуры. Инициализировать можно одним значением, т.е нельзя при
|
||
инициализации локальных переменных пользоваться перечислением заключенным в
|
||
фигурные скобки и операторами <b>FROM</b> и <b>EXTRACT</b>.
|
||
|
||
Имена локальных переменных могут совпадать с именами глобальных
|
||
переменных или процедур, но тогда Вы не сможете обратиться к глобальной
|
||
переменной или вызвать одноименную процедуру.
|
||
|
||
Локальные переменные можно объявлять и в начале блока процедуры. Но
|
||
только до начала тела процедуры. Пример:
|
||
|
||
void proc(){
|
||
int locproc; // объявление локальной процедуры
|
||
locproc=0; // а теперь пошло тело процедуры
|
||
int locproc; // а на это объявление переменной компилятор выдаст сообщение
|
||
// об ошибке, т.к. уже началось тело процедуры
|
||
}
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.5>
|
||
6.5 Динамические переменные и структуры.
|
||
</h2>
|
||
|
||
Наряду с уже известными Вам динамическими процедурами в C-- есть
|
||
возможность использовать динамически и переменные и структуры. Динамические
|
||
переменные и структуры обозначаются также как и динамические процедуры -
|
||
символом двоеточия перед началом их объявления. И также как и динамическая
|
||
процедура, динамическая переменная или структура будет вставлена в код,
|
||
лишь в том случае, если она будет использована в программе.
|
||
|
||
Динамические переменные и структуры найдут применение в библиотеках.
|
||
Использовать их непосредственно в программах нет смысла.
|
||
|
||
У динамических переменных, структур также как и у процедур, есть один
|
||
недостаток - Вы не сможете знать, в каком месте откомпилированного кода они
|
||
будут расположены, и в каком порядке. Но необходимость это знать бывает
|
||
очень редко.
|
||
|
||
Динамические инициализированные переменные и структуры в файле будут
|
||
расположены в его самом конце, после динамических процедур. Эту их
|
||
особенность можно использовать, если Вам будет необходимо, чтобы данные не
|
||
были разбросаны среди кода, а были сгруппированы в одном месте.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.6>
|
||
6.6 Присваивание одного значения нескольким переменным.
|
||
</h2>
|
||
|
||
Если Вам необходимо присвоить нескольким переменным одинаковые значения:
|
||
|
||
var1=0;
|
||
var2=0;
|
||
var3=0;
|
||
|
||
то теперь это можно записать более коротко:
|
||
|
||
var1=var2=var3=0;
|
||
|
||
При использовании такой записи генерируется более компактный и более
|
||
быстрый код.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.1>
|
||
6.7 Переменные типа float.
|
||
|
||
6.7.1 Формат переменных типа float.
|
||
</h2>
|
||
|
||
Для представления значений с плавающей точкой в язык C-- введен тип
|
||
float. Этому типу соответствует действительное число одинарной точности
|
||
FPU.
|
||
|
||
Формат представления данных с плавающей точкой включает три поля:
|
||
знака, мантиссы и порядка. Знак определяется старшим значащим разрядом.
|
||
Поле мантиссы содержит значащие биты числа, а поле порядка содержит
|
||
степень 2 и определяет масштабирующий множитель для мантиссы.
|
||
|
||
31 30.....23 22........0
|
||
| | | | |
|
||
| | | -------------- - поле мантиссы
|
||
| ------------------------ - поле порядка
|
||
--------------------------- - бит знака
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.2>
|
||
6.7.2 Константы с плавающей точкой.
|
||
</h2>
|
||
|
||
Компилятор отличает вещественное число от целого по наличию в нем
|
||
точки. Начинаться вещественное число должно либо цифрой от <b>0</b> до <b>9</b>, либо
|
||
знаком минус. Необязательной частью вещественного числа является
|
||
показатель степени. Показатель степени отделяется от числа символом <b>e</b> или
|
||
<b>E</b>. Пробелы недопустимы. Вот примеры допустимого синтаксиса:
|
||
|
||
0.98
|
||
-15.75
|
||
3.14e2
|
||
1.234567E-20
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.3>
|
||
6.7.3 Диапазон допустимых значений.
|
||
</h2>
|
||
|
||
Вещественное число типа float может находиться в диапазоне от 3.37E38
|
||
до -3.37E38. Минимально близкое к нулю значение равняется 1.17E-38 и
|
||
-1.17E-38. Записывать вещественное число одинарной точности более чем 8
|
||
цифрами не имеет смысла. Показатель степени может принимать значения от
|
||
+38 до -38.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.4>
|
||
6.7.4 Математические операции.
|
||
</h2>
|
||
|
||
Компилятор поддерживает 4 основных действия над переменными типа
|
||
float: сложение, вычитание, умножение и деление. Поддерживается также
|
||
инкремент (var++ - увеличение на 1), декремент (var-- - уменьшение на 1),
|
||
смена знака (-var) и обмен значениями (var1 >< var2). Остальные
|
||
математические операции будут реализованы либо уже реализованы во внешних
|
||
библиотеках. При вычислении значения переменной <b>float</b> можно использовать
|
||
и переменные других типов, они будут автоматически преобразованы в тип
|
||
<b>float</b>.
|
||
|
||
<font color="Red"><b>ВНИМАНИЕ! Составные математические операции выполняются в том
|
||
порядке, в котором они записаны, невзирая на правила арифметики</b></font>.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.5>
|
||
6.7.5 Преобразования типов.
|
||
</h2>
|
||
|
||
При математических операциях конечным итогом которых является
|
||
переменная типа <b>float</b>, все операнды других типов перед вычислением будут
|
||
преобразованы в тип <b>float</b>. При присваивании переменной типа <b>float</b> значения
|
||
переменной другого типа оно также будет преобразовано в тип <b>float</b>.
|
||
|
||
Если при целочисленных вычислениях одним из операндов будет переменная
|
||
типа <b>float</b>, то из него будет выделена целая часть, которая и примет
|
||
участие в вычислениях. При присваивании целочисленной переменной значения
|
||
переменной типа <b>float</b>, из нее также будет выделена целая часть, которая и
|
||
будет присвоена целочисленной переменной.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.6>
|
||
6.7.6 Операции сравнения.
|
||
</h2>
|
||
|
||
Если при операции сравнения левым операндом является переменная или
|
||
выражение типа <b>float</b>, а правым является целочисленное значение, то
|
||
целочисленное значение будет преобразовано в вещественный тип. Если же
|
||
левым операндом является целочисленное выражение или переменная, а правым
|
||
операндом значение типа <b>float</b>, то из правого операнда будет выделена целая
|
||
часть, которая и примет участие в сравнении.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.7.7>
|
||
6.7.7 Сравнение переменных типа float с 32-битным регистром.
|
||
</h2>
|
||
|
||
В регистрах могут содержаться знаковые, без знаковые и вещественные
|
||
данные. По умолчанию считается, что в регистре находится без знаковое целое
|
||
число. При сравнении переменных типа <b>float</b> с 32-битным регистром можно
|
||
указывать тип данных содержащихся в регистре. Для этой цели можно
|
||
использовать модификаторы: <b>signed, unsigned, float</b>. Примеры:
|
||
|
||
float f=1.0;
|
||
|
||
void PROC()
|
||
{
|
||
IF( f < signed ECX) //в регистре ECX находится знаковое число
|
||
IF( unsigned EBX > f) //в регистре EBX находится без знаковое число
|
||
IF( f == float EAX ) //в EAX находится число формата float
|
||
}
|
||
|
||
<font color="Red"><b>ВНИМАНИЕ! При операции сравнения с участием переменой типа float,
|
||
содержимое регистра AX будет разрушено.</b></font>
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=6.8>
|
||
6.8 Указатели.
|
||
</h2>
|
||
|
||
В C-- сейчас указатели реализованы не в полном объеме. Поэтому многие
|
||
вещи, которые возможны в обычных языках <b>C</b>, здесь будут недоступны.
|
||
|
||
Пример применения указателей в C--:
|
||
|
||
char *string[4]={"string1", "string2", "string3", 0}; //массив указателей
|
||
char *str="string4";
|
||
|
||
main()
|
||
int i;
|
||
char *tstr;
|
||
{
|
||
FOR(i=0; string[i]!=0; i++){
|
||
WRITESTR(string[i]);
|
||
WRITELN();
|
||
}
|
||
FOR(tstr=str;byte *tstr!=0; tstr++){
|
||
WRITE(byte *tstr);
|
||
}
|
||
}
|
||
|
||
Указатели можно использовать при передаче параметров процедурам, а в
|
||
самих процедурах в качестве как локальных, так и параметрических
|
||
переменных. Указатели можно также использовать в структурах. Можно
|
||
использовать указатели на указатели. Введена поддержка указателей на
|
||
процедуры:
|
||
|
||
void (*proc)(); //объявление указателя на процедуру
|
||
|
||
По умолчанию указатели на процедуру являются указателями на процедуру в
|
||
стиле <b>pascal</b>, независимо от регистра, в котором написано имя процедуры и
|
||
режима компиляции. Если Вам необходимо, чтобы был использован другой тип
|
||
вызова, то его необходимо указать при объявлении указателя на процедуру.
|
||
|
||
При инициализации указателей компилятор не контролирует то, чем
|
||
инициализируется указатель. Т.е. Вы можете указателю на <b>char</b> присвоить
|
||
указатель на <b>int</b> или указателю на процедуру присвоить адрес переменной.
|
||
Это может вызвать ошибку в работе программы.
|
||
<a href="#contents6"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=7.1>
|
||
7. Адресация.
|
||
|
||
7.1 Относительная адресация.
|
||
</h2>
|
||
|
||
Изначально индексный доступ к элементам в массивах любого типа в
|
||
компиляторе осуществлялся побайтно, независимо от объявленного типа данных.
|
||
Индексы ограничены форматом поля <b>RM</b> процессора 8086, таким образом,
|
||
доступны только следующие форматы индексов (где индекс - значение
|
||
16-разрядной константы или постоянного выражения):
|
||
|
||
variable[index]
|
||
variable[index+BX+SI]
|
||
variable[index+BX+DI]
|
||
variable[index+BP+SI]
|
||
variable[index+BP+DI]
|
||
variable[index+SI]
|
||
variable[index+DI]
|
||
variable[index+BP]
|
||
variable[index+BX]
|
||
|
||
Начиная с версии 0.210, появилась возможность использовать в качестве
|
||
индекса переменных типа <b>char byte int word long dword</b>. При этом
|
||
доступ к элементам массива осуществляется в зависимости от объявленного типа
|
||
массива.
|
||
|
||
Также начиная с версии 0.210 появилась возможность использовать в
|
||
качестве индексных и базовых регистров при относительной адресации любые
|
||
32-битные регистры.
|
||
|
||
Если Вы для адресации к элементам массива будете использовать регистры и
|
||
числовые константы, из которых можно получить поле <b>RM</b> для инструкций 8086
|
||
процессора или комбинацию полей <b>RM BASE и SIB</b> для 80386 процессора, то
|
||
компилятор будет использовать эти регистры для генерации инструкции с этими
|
||
полями. В результате Вы получите относительную побайтную адресацию к
|
||
элементам массива.
|
||
|
||
Если же из этих регистров невозможно получить поля <b>RM, BASE, SIB</b>,
|
||
или для адресации будет использована переменная, то компилятор сначала
|
||
вычислит это выражение в регистр <b>(E)SI</b> или другой, подходящий регистр, а
|
||
затем умножит содержимое этого регистра на разрядность Вашего массива. Таким
|
||
образом, в этом случае вы будете иметь поэлементную адресацию в массиве.
|
||
Пример:
|
||
|
||
AX = var [ 5 ];
|
||
AX = var [ BX + 5 ];
|
||
AX = var [ BX + CX ];
|
||
AX = var [ i ];
|
||
|
||
Компилятор сгенерирует следующий код:
|
||
test.c-- 7: AX=var[5];
|
||
0100 A12501 mov ax,[125h]
|
||
|
||
test.c-- 8: AX=var[BX+5];
|
||
0103 8B872501 mov ax,[bx+125h]
|
||
|
||
test.c-- 9: AX=var[BX+CX];
|
||
0107 89DE mov si,bx
|
||
0109 01CE add si,cx
|
||
010B 01F6 add si,si
|
||
010D 8B842001 mov ax,[si+120h]
|
||
|
||
test.c-- 10: AX=var[i];
|
||
0111 8B362201 mov si,[122h]
|
||
0115 01F6 add si,si
|
||
0117 8B842001 mov ax,[si+120h]
|
||
|
||
Как Вы видите, первые два выражения были преобразованы в одну
|
||
ассемблерную инструкцию, и получилась побайтная адресация. В двух следующих
|
||
выражениях получить одну ассемблерную инструкцию не удалось и компилятор
|
||
применил для этих выражений поэлементную адресацию.
|
||
|
||
Такой двойственный подход реализован с целью сохранения совместимости
|
||
новых возможностей с предыдущими.
|
||
|
||
Несмотря на кажущуюся для неискушенного пользователя путаницу, этот
|
||
механизм легко понять и запомнить по следующему простому правилу: если Вы
|
||
используете в качестве индекса только цифровое значение или регистр <b>BX, SI,
|
||
DI, BP</b> или любой 32-битный регистр, то компилятор сгенерирует код с
|
||
побайтной адресацией. Если же в качестве индекса будет использована
|
||
переменная, то компилятор сгенерирует код с поэлементной адресацией. Если
|
||
же Вы хорошо знакомы с ассемблером, то Вам не составит большого труда
|
||
понять в каких случаях Вы получите побайтную, а в каких поэлементную
|
||
адресацию.
|
||
|
||
Иногда требуется иметь побайтный доступ к элементам массива используя в
|
||
качестве индекса переменную. Например
|
||
|
||
AX=var[i];
|
||
|
||
Для этого выражения будет сгенерирована поэлементная адресация, а нам
|
||
нужна побайтовая. Для этого можно написать так:
|
||
|
||
SI=i;
|
||
AX=var[SI];
|
||
|
||
Но можно это записать короче:
|
||
|
||
AX=DSWORD[#var+i];
|
||
|
||
В обоих этих случаях Вы получите побайтную адресацию к элементам массива
|
||
<b>var</b>. В первом варианте Вы сможете контролировать какой регистр будет
|
||
использован в качестве индекса, а во втором варианте компилятор будет сам
|
||
выбирать регистр для использования в качестве индекса.
|
||
|
||
Важно всегда помнить о двойственном подходе компилятора к вычислению
|
||
адреса в массиве. Еще раз кратко: если Вы в массиве адресуетесь используя
|
||
числовую константу или регистры <b>BX,DI,SI,BP</b> компилятор использует эти
|
||
значения без изменения. Во всех других случаях будет коррекция значения в
|
||
зависимости от типа массива.
|
||
<a href="#contents7"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=7.2>
|
||
7.2 Абсолютная адресация.
|
||
</h2>
|
||
|
||
Абсолютная адресация также возможна. Действуют те же самые ограничения
|
||
на индексы, что и при относительной адресации.
|
||
|
||
Вычисленный индекс будет абсолютен в сегменте, регистр которого указан.
|
||
Можно указывать любой из регистров <b>DS, CS, SS и ES</b>. На процессорах 80386 и
|
||
более новых можно указывать также регистры <b>FS и GS</b>.
|
||
|
||
Синтаксис - точно такой же, как и в относительной адресации, за
|
||
исключением того, что указывается не переменная, а сегмент и тип данных.
|
||
Могут применяться следующие указатели:
|
||
|
||
// адресация в сегменте данных
|
||
DSBYTE [смещение] // адресует байт в сегменте DS
|
||
DSWORD [смещение] // адресует слово в сегменте DS
|
||
DSCHAR [смещение] // адресует char в сегменте DS
|
||
DSINT [смещение] // адресует int в сегменте DS
|
||
DSDWORD [смещение] // адресует dword в сегменте DS
|
||
DSLONG [смещение] // адресует long в сегменте DS
|
||
DSFLOAT [смещение] // адресует float в сегменте DS
|
||
|
||
// адресация в сегменте кода
|
||
CSBYTE [смещение] // адресует байт в сегменте CS
|
||
CSWORD [смещение] // адресует слово в сегменте CS
|
||
CSCHAR [смещение] // адресует char в сегменте CS
|
||
CSINT [смещение] // адресует int в сегменте CS
|
||
CSDWORD [смещение] // адресует dword в сегменте CS
|
||
CSLONG [смещение] // адресует long в сегменте CS
|
||
CSFLOAT [смещение] // адресует float в сегменте CS
|
||
|
||
// адресация в сегменте стека
|
||
SSBYTE [смещение] // адресует байт в сегменте SS
|
||
SSWORD [смещение] // адресует слово в сегменте SS
|
||
SSCHAR [смещение] // адресует char в сегменте SS
|
||
SSINT [смещение] // адресует int в сегменте SS
|
||
SSDWORD [смещение] // адресует dword в сегменте SS
|
||
SSLONG [смещение] // адресует long в сегменте SS
|
||
SSFLOAT [смещение] // адресует float в сегменте SS
|
||
|
||
// адресация в дополнительном сегменте данных
|
||
ESBYTE [смещение] // адресует байт в сегменте ES
|
||
ESWORD [смещение] // адресует слово в сегменте ES
|
||
ESCHAR [смещение] // адресует char в сегменте ES
|
||
ESINT [смещение] // адресует int в сегменте ES
|
||
ESDWORD [смещение] // адресует dword в сегменте ES
|
||
ESLONG [смещение] // адресует long в сегменте ES
|
||
ESFLOAT [смещение] // адресует float в сегменте ES
|
||
|
||
// адресация в дополнительном сегменте 2 (80386) +
|
||
FSBYTE [смещение] // адресует байт в сегменте FS
|
||
FSWORD [смещение] // адресует слово в сегменте FS
|
||
FSCHAR [смещение] // адресует char в сегменте FS
|
||
FSINT [смещение] // адресует int в сегменте FS
|
||
FSDWORD [смещение] // адресует dword в сегменте FS
|
||
FSLONG [смещение] // адресует long в сегменте FS
|
||
FSFLOAT [смещение] // адресует float в сегменте FS
|
||
|
||
// адресация в дополнительном сегменте 3 (80386) +
|
||
GSBYTE [смещение] // адресуют байт в сегменте GS
|
||
GSWORD [смещение] // адресуют слово в сегменте GS
|
||
GSCHAR [смещение] // адресуют char в сегменте GS
|
||
GSINT [смещение] // адресуют int в сегменте GS
|
||
GSDWORD [смещение] // адресуют dword в сегменте GS
|
||
GSLONG [смещение] // адресуют long в сегменте GS
|
||
GSFLOAT [смещение] // адресует float в сегменте GS
|
||
|
||
Примеры:
|
||
Загрузить в AL байт из ячейки с шестнадцатеричным адресом 0000:0417
|
||
ES = 0x0000;
|
||
AL = ESBYTE [0x417];
|
||
|
||
Переместить слово из ячейки с шестнадцатеричным адресом 2233:4455
|
||
в ячейку с шестнадцатеричным адресом A000:0002
|
||
$PUSH DS
|
||
DS = 0x2233;
|
||
ES = 0xA000;
|
||
ESWORD [0x0002] = DSWORD [0x4455];
|
||
$POP DS
|
||
|
||
Сохранить вычисленное значение выражения X + 2, имеющее
|
||
тип int в ячейке с шестнадцатеричным адресом FFFF:1234
|
||
ES = 0xFFFF;
|
||
ESINT [0x1234] = X + 2;
|
||
|
||
Сохранить BX в сегменте стека по смещению 42:
|
||
SSWORD [42] = BX;
|
||
<a href="#contents7"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.1>
|
||
8. Работа с блоками данных.
|
||
|
||
8.1 Структуры.
|
||
|
||
8.1.1 Что такое структуры.
|
||
</h2>
|
||
|
||
Структура позволяет объединить в одном объекте совокупность значений,
|
||
которые могут иметь различные типы.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.2>
|
||
8.1.2 Синтаксис.
|
||
</h2>
|
||
|
||
struct [<тег>] { <список-объявлений-элементов> }
|
||
<описатель>[,<описатель>...];
|
||
struct <тег> <описатель> [,<описатель>];
|
||
|
||
Объявление структуры начинается с ключевого слова struct и имеет две
|
||
формы записи.
|
||
|
||
В первой форме типы и имена элементов структуры специфицируются в
|
||
списке-объявлений-элементов. Необязательный в данном случае <b>тег</b> - это
|
||
идентификатор, который именует структурный тип, определенный данным
|
||
списком объявлений элементов. <b>описатель</b> специфицирует либо переменную
|
||
структурного типа, либо массив структур данного типа.
|
||
|
||
Вторая синтаксическая форма объявления использует тег структуры для
|
||
ссылки на структурный тип, определенный где-то в другом месте программы.
|
||
|
||
Список объявлений элементов представляет собой последовательность из
|
||
одной или более объявлений переменных. Каждая переменная, объявленная в
|
||
этом списке, называется элементом структуры.
|
||
|
||
Элементы структуры запоминаются в памяти последовательно в том
|
||
порядке, в котором они объявляются. Выравнивание элементов внутри
|
||
структуры по умолчанию не производится. Но существует опция, включение
|
||
которой в командную строку позволяет иметь выравнивание и внутри
|
||
структуры. Сама структура выравнивается на четный адрес если включено
|
||
выравнивание.
|
||
|
||
Примеры объявлений структур:
|
||
|
||
struct test
|
||
{
|
||
int a;
|
||
char b[8];
|
||
long c;
|
||
} rr, ff[4];
|
||
|
||
В этом примере объявлены структура с именем <b>rr</b> и массив из 4 структур
|
||
с именем <b>ff</b>. Всему набору переменных присвоено название <b>(тег) test</b>. Этот
|
||
тег можно использовать для объявления других структур. Например:
|
||
|
||
struct test dd;
|
||
|
||
Здесь объявлена структура с именем <b>dd</b>, имеющая набор элементов
|
||
описанных в теге <b>test</b>.
|
||
|
||
При объявлении структур с ранее объявленным тегом ключевое слово
|
||
<b>struct</b> можно не писать. Т.е можно написать вот так:
|
||
|
||
test dd;
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.3>
|
||
8.1.3 Инициализация структур при объявлении.
|
||
</h2>
|
||
|
||
После объявления структуры ее элементы могут принимать произвольные
|
||
значения. Что бы этого не было надо структуры проинициализировать.
|
||
Инициализировать структуры при их объявлении можно только глобальные. C--
|
||
поддерживает несколько способов инициализации структур при их объявлении:
|
||
|
||
1. Одним значением:
|
||
|
||
struct test dd=2;
|
||
|
||
В этом примере всем элементам структуры dd присваивается значение 2.
|
||
|
||
2. Массивом значений:
|
||
|
||
struct test dd={1,2,,6};
|
||
|
||
В этом примере первому элементу структуры dd присваивается значение 1,
|
||
второму - 2, четвертому - 6. Пропущенным и не доинициализированным
|
||
значениям будет присвоено 0 значение.
|
||
|
||
3. Командой FROM:
|
||
|
||
struct test dd=FROM "file.dat";
|
||
|
||
В этом примере на место где расположена структура dd при компиляции будет
|
||
загружено содержимое файла <file.dat>. Если размер файла больше чем размер
|
||
структуры, то лишние байты будут загружены в код программы, но они не
|
||
будут востребованы. Если размер файла меньше чем размер структуры, то
|
||
недостающие байты структуры будут заполнены нулями.
|
||
|
||
4. Командой EXTRACT:
|
||
|
||
struct test dd=EXTRACT "file.dat", 24, 10;
|
||
|
||
В этом примере на место где расположена структура dd при компиляции будет
|
||
загружен фрагмент из файла <b>file.dat</b> длиной 10 байт со смещения 24.
|
||
Недостающие байты будут заполнены нулями.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.4>
|
||
8.1.4 Инициализация структуры при выполнении программы.
|
||
</h2>
|
||
|
||
При выполнении программы, кроме присвоения каждому элементу структуры
|
||
значения, можно проинициализировать всю структуру присвоением ей числа или
|
||
переменной. Примеры:
|
||
|
||
void proc()
|
||
struct test aa[5],rr;
|
||
int i;
|
||
{
|
||
aa[0]=0x12345678;
|
||
aa[i]=int 0x12345678;
|
||
aa=long 0x12345678;
|
||
rr=i;
|
||
|
||
В первом примере память, занимаемая первой структурой массива из 5
|
||
структур, будет заполнена байтом 0x78 (по умолчанию).
|
||
|
||
Во втором примере память, занимаемая (i+1)-вой структурой массива из 5
|
||
структур, будет заполнена словом 0x5678.
|
||
|
||
В третьем примере память, занимаемая всем массивом из 5 структур, будет
|
||
заполнена длинным словом 0x12345678.
|
||
|
||
В четвертом примере память, занимаемая структурой rr, будет заполнена
|
||
содержимым переменной i.
|
||
|
||
Можно также копировать содержимое одной структуры в другую. Например:
|
||
|
||
rr=aa[2];
|
||
|
||
Будет скопировано содержимое третьей структуры массива структур aa в
|
||
структуру rr.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.5>
|
||
8.1.5 Операции с элементами структур.
|
||
</h2>
|
||
|
||
С элементами структур можно выполнять все те операции, которые
|
||
доступны для переменных соответствующего типа. Например: Объявлена
|
||
структура:
|
||
|
||
struct test
|
||
{
|
||
int a;
|
||
char b[8];
|
||
long c;
|
||
} rr[3];
|
||
Пример допустимого синтаксиса:
|
||
rr.a = rr.b[i] * rr[1].c + i ;
|
||
|
||
Примечание:
|
||
При операциях с элементами массива структур и с индексированными
|
||
элементами, в которых в качестве индекса или номера структуры используется
|
||
переменная, компилятор может использовать регистры SI и DI, а в некоторых
|
||
ситуациях (например: rr[i].b[j] >< rr[i+1].b[j+2] ) будет задействован и
|
||
регистр DX.
|
||
|
||
Для отдельных элементов структуры, можно получать их адрес, размер
|
||
и смещение в теге структуры. Вот пример:
|
||
|
||
struct AA //объявление тега структуры
|
||
{
|
||
word a[3]; // первый элемент структуры
|
||
char b; // второй элемент структуры
|
||
long c; // третий элемент структуры
|
||
};
|
||
|
||
struct BB //тег второй структуры
|
||
{
|
||
word aa; // первый элемент
|
||
AA bb; // второй элемент - вложенная структура
|
||
}ss; // объявляем структуру с тегом <b>BB</b>
|
||
|
||
void proc()
|
||
{
|
||
AX=#ss.bb.b; // получить адрес элемента <b>b</b> структуры <b>bb</b> в структуре <b>ss</b>
|
||
AX=#BB.bb.b; // получить смещение этого же элемента в теге <b>BB</b>
|
||
AX=sizeof(ss.bb); // получить размер элемента <b>bb</b> в структуре <b>ss</b>
|
||
AX=sizeof(BB.bb); // получить размер элемента <b>bb</b> в теге <b>BB</b>
|
||
}
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.6>
|
||
8.1.6 Вложенные структуры.
|
||
</h2>
|
||
|
||
При объявлении тегов структур можно использовать теги других,
|
||
объявленных ранее структур. Пример вложенных структур:
|
||
|
||
struct RGB
|
||
{
|
||
byte Red;
|
||
byte Green;
|
||
byte Blue;
|
||
byte Reserved;
|
||
};
|
||
|
||
struct BMPINFO
|
||
{
|
||
struct BMPHEADER header; //описание этой структуры пропущено
|
||
struct RGB color[256];
|
||
}info;
|
||
|
||
Предположим Вам нужно получить содержимое переменной <b>Red</b> десятого
|
||
элемента <b>color</b>. Это можно будет записать так:
|
||
|
||
AL=info.color[10].Red;
|
||
|
||
Но существует одно ограничение использования вложенных структур в C--.
|
||
Это невозможность использования переменной в качестве индекса более одного
|
||
раза при обращении к многоэкземплярным структурам. Поясним это на примере:
|
||
|
||
struct ABC
|
||
{
|
||
int a;
|
||
int b;
|
||
int c;
|
||
};
|
||
|
||
struct
|
||
{
|
||
struct ABC first[4]; //4 экземпляра структуры ABC
|
||
int d;
|
||
}second[4];
|
||
|
||
int i,j;
|
||
|
||
void proc()
|
||
{
|
||
AX=second[i].first[j].a; //такая запись вызовет сообщение об ошибка, так
|
||
//как переменная использовалась в двух местах
|
||
AX=second[2].first[j].a; //а этот синтаксис допустим.
|
||
AX=second[i].first[3].a;
|
||
}
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.7>
|
||
8.1.7 Отображение тега структуры на блок памяти.
|
||
</h2>
|
||
|
||
Отображение тега структуры на блок памяти является альтернативой
|
||
указателям на структуры.
|
||
|
||
Альтернативный способ использования указателей на структуры позволит
|
||
Вам самим выбрать регистр, в котором будет хранится адрес структуры и
|
||
самим следить за его сохранностью и по мере необходимости восстанавливать
|
||
его содержимое.
|
||
|
||
Объяснить, как использовать отображение тега структуры на память,
|
||
наверное, будет проще на примере:
|
||
|
||
struct AA //объявление тега структуры
|
||
{
|
||
word a[3]; // первый элемент структуры
|
||
char b; // второй элемент структуры
|
||
long c; // третий элемент структуры
|
||
};
|
||
|
||
byte buf[256]; //блок памяти, на который будет отображен тег структуры
|
||
|
||
void proc1()
|
||
{
|
||
...
|
||
proc2 ( #buf ); // вызов процедуры с передачей ей в качестве параметра
|
||
// адреса блока памяти
|
||
...
|
||
}
|
||
|
||
long proc2 (unsigned int pointer_to_mem)
|
||
{
|
||
int i;
|
||
BX=pointer_to_mem; // в BX загрузим адрес блока памяти
|
||
FOR(i=0; i<3; i++){ // в массив элемента <b>a</b> записать -1
|
||
BX.AA.a[i]=-1;
|
||
}
|
||
BX.AA.b=0;
|
||
ES:BX.AA.c=EAX;
|
||
return BX.AA.c; // вернуть содержимое элемента <b>c</b>
|
||
}
|
||
|
||
В 16-битном режиме для хранения адреса структуры можно использовать
|
||
регистры: <b>BX,DI,SI,BP</b>. Но лучше для этого использовать регистр <b>BX</b>.
|
||
Регистры <b>DI и SI</b> может использовать компилятор при вычислении адреса
|
||
многоэлементных объектов. Регистр <b>BP</b> компилятор использует для работы с
|
||
локальными и параметрическими переменными. В 32-битном режиме можно
|
||
использовать любой кроме <b>ESP и EBP</b> регистр, а регистры <b>EDI и ESI</b> надо
|
||
использовать осторожно.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.1.8>
|
||
8.1.8 Битовые поля структур.
|
||
</h2>
|
||
|
||
Битовые поля структур используются для экономии памяти, поскольку
|
||
позволяют плотно упаковать значения, и для организации удобного доступа к
|
||
регистрам внешних устройств, в которых различные биты могут иметь
|
||
самостоятельное функциональное назначение.
|
||
|
||
Объявление битового поля имеет следующий синтаксис:
|
||
|
||
<тип> [<идентификатор>]:<константа>;
|
||
|
||
или на примере:
|
||
|
||
int var:5; //объявление битового поля размером 5 бит с именем <b>var</b>
|
||
|
||
Битовое поле состоит из некоторого числа битов, которое задается
|
||
числовым выражением <b>константа</b>. Его значение должно быть целым
|
||
положительным числом и его значение не должно превышать числа разрядов,
|
||
соответствующие <b>типу</b> определяемого битового поля. В C-- битовые поля
|
||
могут содержать только без знаковые значения. Нельзя использовать массивы
|
||
битовых полей, указатели на битовые поля.
|
||
|
||
<b> идентификатор</b> именует битовое поле. Его наличие необязательно.
|
||
Неименованное битовое поле означает пропуск соответствующего числа битов
|
||
перед размещением следующего элемента структуры. Неименованное битовое
|
||
поле, для которого указан нулевой размер, имеет специальное назначение:
|
||
оно гарантирует, что память для следующего битового поля будет начинаться
|
||
на границе того типа, который задан для неименованного битового поля.
|
||
Т.е. будет произведено выравнивание битового поля на 8/16/32 бита.
|
||
|
||
В C-- все битовые поля упаковываются одно за другим независимо от
|
||
границ типа идентификаторов. Если последующее поле не является битовым
|
||
полем, то оставшиеся до границы байта биты не будут использованы.
|
||
Максимальный размер битового поля равен 32 бита для типа <b>dword/long</b>, 16
|
||
бит для типа <b>word/int</b> и 8 бит для типа <b>byte/char</b>. Битовые поля можно
|
||
объединять, т.е. использовать их в операторе<b> union. sizeof</b>
|
||
примененный к битовому полю вернет размер этого поля в битах. При
|
||
использовании битового поля, его содержимое будет расширятся в регистр
|
||
как без знаковое целое число.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.2>
|
||
8.2 Объединения.
|
||
</h2>
|
||
|
||
Объединения позволяют в разные моменты времени хранить в одном объекте
|
||
значения различного типа.
|
||
|
||
Память, которая выделяется под объединение, определяется размером
|
||
наиболее длинного из элементов объединения. Все элементы объединения
|
||
размещаются в одной и той же области памяти с одного и того же адреса.
|
||
Значение текущего элемента объединения теряется, когда другому элементу
|
||
объединения присваивается значение.
|
||
|
||
В C-- реализованы так называемые анонимные объединения. Т.е.
|
||
объединениям не присваивается имя, а обращение к элементам объединения
|
||
происходит как к обычной переменной. Пример:
|
||
|
||
union
|
||
{
|
||
dword regEAX;
|
||
word regAX;
|
||
byte regAL;
|
||
}; // объявили, что 3 переменные расположены по одному и тому же
|
||
// физическому адресу
|
||
|
||
void test()
|
||
{
|
||
regEAX = 0x2C;
|
||
BL = regAL; //в регистре BL окажется значение 0x2C
|
||
}
|
||
|
||
Объединять можно переменные различных типов, массивы, строковые
|
||
переменные и структуры. Объединения могут быть глобальными и локальными, а
|
||
также располагаться внутри структур (пока в объединениях внутри структур
|
||
нельзя использовать структуры). Глобальные объединения могут быть
|
||
инициализированными и неинициализированными. Чтобы получить
|
||
инициализированное объединение достаточно проинициализировать лишь первый
|
||
элемент объединения. Если же первый элемент объединения не инициализирован,
|
||
а следующие элементы инициализированы, то это вызовет сообщение компилятора
|
||
об ошибке.
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=8.3>
|
||
8.3 Команды 'FROM' и 'EXTRACT'.
|
||
</h2>
|
||
|
||
В C-- есть очень оригинальные команды, которых нет в других языках. Это
|
||
<b>FROM и EXTRACT</b>.
|
||
|
||
Команда <b>FROM</b> имеет синтаксис:
|
||
|
||
<тип_переменной> <имя_переменной> = FROM <имя_файла>;
|
||
|
||
Встретив эту команду при компиляции, компилятор загрузит в выходной
|
||
файл содержимое файла <b>имя_файла</b>, а <b>имя_переменной</b> будет идентификатором
|
||
начала загруженного кода. Вот пример использования этой команды из файла
|
||
tinydraw.c--:
|
||
|
||
byte palette[PALSIZE] = FROM "TINYDRAW.PAL"; // buffer for palette
|
||
|
||
Команда <b>EXTRACT</b> имеет синтаксис:
|
||
|
||
<тип_переменной> <имя_переменной> = EXTRACT <имя_файла>, <начало>, <длина>;
|
||
|
||
Встретив эту команду при компиляции, компилятор загрузит в выходной
|
||
файл из файла <b>имя_файла</b> число байт равное <b>длина</b> со смещения <b>начало</b>, а
|
||
<b>имя_переменной</b> будет идентификатором начала загруженного кода. Вот пример
|
||
использования этой команды:
|
||
|
||
byte LIT128 = EXTRACT "8X16.FNT", 16*128, 16;
|
||
byte LIT130 = EXTRACT "8X16.FNT", 16*130, 16;
|
||
<a href="#contents8"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.1>
|
||
9. Операторы.
|
||
|
||
9.1 Условные инструкции.
|
||
</h2>
|
||
|
||
Условные инструкции, при помощи которых осуществляется ветвление, такие
|
||
же как в C.
|
||
|
||
C-- имеет две инструкции ветвления. <b>if и IF</b>.
|
||
|
||
<b>if</b> делает близкий условный переход, а <b>IF</b> делает короткий
|
||
(8-разрядный) условный переход. <b>IF</b> выполняется быстрее и может экономить
|
||
до 3 байт в размере кода, но может осуществлять переходы только в пределах
|
||
127 байтов кода.
|
||
|
||
Условные инструкции, как и в <b>C</b>, могут сопровождаться, как одиночной
|
||
командой, так и блоком из нескольких команд, заключенных в фигурные скобки
|
||
{ и }. Условные инструкции имеют те же ограничения, что и условные
|
||
выражения.
|
||
|
||
Если за инструкцией <b>IF</b> следует больше чем 127 байтов кода, транслятор
|
||
выдаст следующее сообщение об ошибке:
|
||
|
||
IF jump distance too far, use if.
|
||
|
||
Это можно просто исправить, заменив в этом месте инструкцию <b>IF</b> на <b>if</b>.
|
||
|
||
Команды <b>else и ELSE</b> используются точно так же, как в языке <b>C</b>.
|
||
Отличие их в том, что <b>ELSE</b> имеет ограничение адреса перехода 127 байт,
|
||
такое же как <b>IF. else</b> генерирует код на 1 байт длиннее, чем <b>ELSE</b>.
|
||
|
||
Команды <b>IF и else</b>, а также <b>if и ELSE</b> могут свободно смешиваться
|
||
как в следующем примере:
|
||
|
||
if( x == 2 )
|
||
WRITESTR("Two");
|
||
ELSE{ WRITESTR("not two.");
|
||
printmorestuff();
|
||
}
|
||
|
||
Если за инструкцией <b>ELSE</b> следует больше чем 127 байтов кода,
|
||
транслятор выдаст следующее сообщение об ошибке:
|
||
|
||
ELSE jump distance too far, use else.
|
||
|
||
Это можно просто исправить, заменив в этом месте инструкцию <b>ELSE</b> на
|
||
<b>else</b>.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.2>
|
||
9.2 Циклы do{} while.
|
||
</h2>
|
||
|
||
В таком цикле блок кода, составляющий тело цикла, будет повторяться,
|
||
пока условное выражение имеет значение <b>истинно</b>.
|
||
|
||
Истинность условного выражения проверяется после выполнения тела цикла,
|
||
поэтому блок кода будет выполнен, по крайней мере, один раз.
|
||
|
||
Пример <b>do {} while</b> цикла, в котором тело будет исполнено пять раз:
|
||
|
||
count = 0;
|
||
do {
|
||
count++;
|
||
WRITEWORD(count);
|
||
WRITELN();
|
||
} while (count < 5);
|
||
|
||
Условное выражение в <b>do {} while</b> инструкции должно соответствовать тем же
|
||
правилам, что и в инструкциях <b>IF и if</b>.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.3>
|
||
9.3 Циклы loop, LOOPNZ, loopnz.
|
||
</h2>
|
||
|
||
Циклы <b>loop</b> повторяют блок кода, пока определенная переменная или
|
||
регистр, выполняющие роль счетчика цикла, содержат значение, отличное от
|
||
нуля. В конце выполнения блока кода, составляющего тело цикла, указанная
|
||
переменная или регистр - уменьшается на 1, а затем проверяется на равенство
|
||
нулю. Если переменная (или регистр) не равна нулю, тело цикла будет
|
||
выполнено снова, и процесс повторится.
|
||
|
||
Пример использования цикла <b>loop</b> в котором в качестве счетчика цикла
|
||
использована переменная:
|
||
|
||
count = 5;
|
||
loop( count )
|
||
{WRITEWORD(count);
|
||
WRITELN();
|
||
}
|
||
|
||
Наибольший эффект дает использование регистра CX для циклов с небольшим
|
||
телом, поскольку в этом случае компилятором генерируется цикл с применением
|
||
машинной команды <b>LOOP</b>.
|
||
|
||
Если перед стартом счетчик циклов содержит нулевое значение, команды
|
||
тела цикла будут выполнены максимальное число раз для диапазона переменной
|
||
(256 раз для 8-битного счетчика (переменной типа <b>byte</b> или <b>char</b>), 65536 для
|
||
16-битного счетчика (переменной типа <b>word</b> или <b>int</b>), и 4294967296 для
|
||
32-битного счетчика (переменной типа <b>dword</b> или <b>long</b>).
|
||
|
||
В следующем примере цикл будет выполнен 256 раз:
|
||
|
||
BH = 0;
|
||
loop (BH)
|
||
{
|
||
}
|
||
|
||
Если в команде не указано никакого счетчика цикла, цикл будет
|
||
продолжаться бесконечно.
|
||
|
||
Следующий пример будет непрерывно выводить символ звездочки (*) на
|
||
экран:
|
||
|
||
loop()
|
||
WRITE('*');
|
||
|
||
Программист, если хочет, может использовать или изменять значение
|
||
переменной счетчика цикла внутри цикла.
|
||
|
||
Например, следующий цикл выполнится только 3 раза:
|
||
|
||
CX = 1000;
|
||
loop( CX )
|
||
{
|
||
IF( CX > 3 )
|
||
CX = 3;
|
||
}
|
||
|
||
Цикл можно также прервать оператором разрыва <b>BREAK</b> или <b>break</b>. Вот
|
||
тот же пример с использованием <b>BREAK</b>:
|
||
|
||
CX = 1000;
|
||
loop( CX )
|
||
{
|
||
IF( CX > 3 )
|
||
BREAK;
|
||
}
|
||
|
||
Циклы <b>LOOPNZ/loopnz</b> отличаются от цикла <b>loop</b>, тем, что перед входом
|
||
в цикл проверяется равенство нулю аргумента цикла. Если аргумент равен
|
||
нулю, то тело цикла ни разу не выполнится (в цикле <b>loop</b> в этом случае
|
||
тело цикла выполнится максимальное число раз). Цикл <b>LOOPNZ</b> получается
|
||
максимально эффективным при оптимизации на размер кода, если в качестве
|
||
параметра-счетчика используется регистр <b>CX/ECX</b>. При этом компилятор
|
||
использует ассемблерные инструкции <b>JCXZ/JECXZ и LOOP</b>.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.4>
|
||
9.4 Цикл while, WHILE.
|
||
</h2>
|
||
|
||
Синтаксис:
|
||
while(<выражение>)
|
||
<оператор>
|
||
|
||
Цикл выполняется до тех пор, пока значение <b>выражения</b> не станет
|
||
ложным. Вначале вычисляется <b>выражение</b>. Если <b>выражение</b> изначально ложно,
|
||
то тело оператора <b>while</b> вообще не выполняется и управление сразу
|
||
передается на следующий оператор программы.
|
||
|
||
Цикл <b>WHILE</b> аналогичен циклу <b>while</b>, но при этом генерируется код на
|
||
3 байта короче. Размер сгенерированного кода в цикле <b>WHILE</b> должен быть
|
||
меньше 127 байт.
|
||
|
||
Примеры:
|
||
while ( i < 20 ){
|
||
WRITEWORD(i);
|
||
i++;
|
||
}
|
||
|
||
WHILE (i < 20 ) @WRITEWORD(i); //цикл либо будет бесконечным либо не
|
||
//выполнится ни разу
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.5>
|
||
9.5 Цикл for, FOR.
|
||
</h2>
|
||
|
||
Синтаксис:
|
||
for ([<начальное выражение>]; [<условие>]; [<приращение>])
|
||
<оператор>
|
||
|
||
Цикл <b>for</b> выполняется до тех пор, пока значение <b>условия</b> не станет
|
||
ложным. Если <b>условие</b> изначально ложно, то тело оператора <b>for</b> вообще не
|
||
выполняется и управление сразу передается на следующий оператор программы.
|
||
<b>Начальное выражение</b> и <b>приращение</b> обычно используются для инициализации
|
||
и модификации параметров цикла.
|
||
|
||
Первым шагом при выполнении <b>for</b> является вычисление <b>начального
|
||
выражения</b>, если оно имеется. Затем вычисляется <b>условие</b> и производится
|
||
его оценка следующим образом:
|
||
|
||
1) Если <b>условие</b> истинно, то выполняется тело оператора. Затем
|
||
вычисляется <b>приращение</b> (если оно есть), и процесс повторяется.
|
||
|
||
2) Если <b>условие</b> опущено, то его значение принимается за истину. В
|
||
этом случае цикл for представляет бесконечный цикл, который может
|
||
завершиться только при выполнении в его теле операторов <b>break, goto,
|
||
return</b>.
|
||
|
||
3) Если <b>условие</b> ложно, то выполнение цикла <b>for</b> заканчивается и
|
||
управление передается следующему оператору.
|
||
|
||
Цикл <b>FOR</b> аналогичен циклу <b>for</b>, но при этом генерируется код на 3
|
||
байта короче. Размер сгенерированного кода в цикле <b>FOR</b> должен быть меньше
|
||
127 байт.
|
||
|
||
Примеры:
|
||
for(i=0;i<5;i++){
|
||
WRITESTR("СТРОКА ");
|
||
WRITEWORD(i);
|
||
WRITELN();
|
||
}
|
||
|
||
Число <b>начальных выражений</b> и число <b>приращений</b> не ограничено. Каждый
|
||
оператор в <b>начальных выражениях</b> и <b>приращениях</b> должен разделяться
|
||
запятой. Пример:
|
||
|
||
for ( a=1, b=2 ; a<5 ; a++, b+=a ) {...
|
||
|
||
Также есть возможность логического объединения <b>условий</b>. Объединять
|
||
можно до 32 условий. Каждое объединяемое условие должно быть заключено в
|
||
скобки. Пример:
|
||
|
||
for ( a=0 ; (a>=0) && (a<10) ; a++ ){...
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.6>
|
||
9.6 Оператор переключатель switch.
|
||
</h2>
|
||
|
||
Синтаксис:
|
||
switch(<выражение>){
|
||
case <константа>:
|
||
<оператор>
|
||
...
|
||
case <константа>:
|
||
<оператор>
|
||
...
|
||
...
|
||
default:
|
||
<оператор>
|
||
}
|
||
Оператор переключатель <b>switch</b> предназначен для выбора одного из
|
||
нескольких альтернативных путей выполнения программы. Выполнение начинается
|
||
с вычисления значения <b>выражения</b>. После этого управление передается одному
|
||
из <b>операторов</b> тела переключателя. В теле переключателя содержатся
|
||
конструкции: <b>case константа:</b>, которые синтаксически представляют собой
|
||
метки операторов. Оператор, получающий управление, - это тот оператор,
|
||
значение константы которого совпадают со значением <b>выражения</b>
|
||
переключателя. Значение <b>константы</b> должно быть уникальным.
|
||
|
||
Выполнение тела оператора-переключателя <b>switch</b> начинается с выбранного
|
||
таким образом оператора, и продолжается до конца тела или до тех пор, пока
|
||
какой-либо оператор не передаст управление за пределы тела.
|
||
|
||
Оператор, следующий за ключевым словом <b>default</b>, выполняется, если ни
|
||
одна из констант не равна значению <b>выражения</b>. Если <b>default</b> опущено, то
|
||
ни один оператор в теле переключателя не выполняется, и управление
|
||
передается на оператор, следующий за <b>switch</b>.
|
||
|
||
Для выхода из тела переключателя обычно используется оператор разрыва
|
||
<b>break (BREAK)</b>.
|
||
|
||
Пример:
|
||
switch (i){
|
||
case 'A':
|
||
WRITE(i);
|
||
i++;
|
||
BREAK;
|
||
case 32:
|
||
WRITE('_');
|
||
i++;
|
||
BREAK;
|
||
default:
|
||
WRITE('i');
|
||
}
|
||
|
||
Оператор <b>switch</b> сейчас в компиляторе может реализовываться трем
|
||
способами: двухтабличным, табличным и методом последовательных проверок.
|
||
|
||
Табличный метод является самым быстрым, а при большом числе операторов
|
||
<b>case</b> и при незначительной разнице между максимальным и минимальным
|
||
значениями <b>case</b> он еще может быть и более компактным. Но у него есть и
|
||
недостатки: в 16-битном режиме компилятор всегда использует регистр BX, а в
|
||
32-битном режиме, если операндом <b>switch</b> является регистр, то его значение
|
||
будет разрушено.
|
||
|
||
В методе последовательных проверок блок сравнений находится в начале
|
||
тела оператора <b>switch</b>, это позволяет избавиться от 1-2 лишних <b>jmp</b>. Но
|
||
компилятор не может определить, какой тип перехода использовать при
|
||
проверке значений <b>case</b>. Это будет Вашей заботой. Если размер кода от
|
||
начала тела оператора <b>switch</b> до места расположения оператора <b>case</b>
|
||
меньше 128 байт, можно использовать короткий переход. В этом случае Вы
|
||
можете указать оператор <b>CASE</b>, что приведет к генерации более компактного
|
||
кода. Компилятор в предупреждениях будет Вам подсказывать о возможности
|
||
использования операторов <b>CASE</b>. Использование оператора <b>CASE</b> в случаях,
|
||
когда размер блока кода более 128 байт приведет к выдаче компилятором
|
||
сообщения об ошибке.
|
||
|
||
При двухтабличном методе создаются две таблицы - таблица адресов входа в
|
||
тело оператора <b>switch/SWITCH</b> и таблица значений <b>case</b>. Генерируется
|
||
процедура сравнения входного значения со значениями во второй таблице. Если
|
||
есть совпадение, то делается переход по адресу из второй таблицы. Этот
|
||
метод является самым медленным, но при большом числе значений <b>case</b> (более
|
||
15) он становится самым компактным.
|
||
|
||
При оптимизации кода на размер, компилятор предварительно вычисляет
|
||
размер кода, который может быть получен всеми методами и реализует самый
|
||
компактный. При оптимизации на скорость преимущество отдается табличному
|
||
методу, если размер таблицы получается не слишком большим.
|
||
|
||
Для оператора <b>switch</b> введена также и короткая его форма - <b>SWITCH</b>.
|
||
Ее можно применять в случае, если размер блока кода между началом тела
|
||
оператора и оператором <b>default</b> (если он отсутствует, то концом тела
|
||
оператора <b>switch</b>) меньше 128 байт. О возможности использования короткой
|
||
формы компилятор будет сообщать в предупреждениях.
|
||
|
||
Для оператора <b>case/CASE</b>, который может использоваться только в теле
|
||
блока оператора <b>switch/SWITCH</b>, можно указывать диапазон значений. Сначала
|
||
надо указывать меньшее значение, затем после многоточия большее. Пример:
|
||
|
||
switch(AX){
|
||
case 1...5:
|
||
WRITESTR("Range AX from 1 to 5");
|
||
BREAK;
|
||
};
|
||
|
||
Раньше Вам бы пришлось писать более громоздкую конструкцию:
|
||
|
||
switch(AX){
|
||
case 1:
|
||
case 2:
|
||
case 3:
|
||
case 4:
|
||
case 5:
|
||
WRITESTR("Range AX from 1 to 5");
|
||
BREAK;
|
||
};
|
||
|
||
Кроме того, что новый формат записи более компактен и более читабелен,
|
||
но еще при этом компилятор создает более компактный и быстрый код.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.7>
|
||
9.7 Оператор перехода goto, GOTO.
|
||
</h2>
|
||
|
||
Синтаксис:
|
||
goto <метка>;
|
||
.
|
||
.
|
||
.
|
||
<метка>:
|
||
|
||
Оператор перехода <b>goto</b> передает управление на <b>оператор</b> помеченный
|
||
<b>меткой</b>. Аналогом в ассемблере оператору goto является команда <b>jmp near</b>.
|
||
Аналогом в ассемблере оператору <b>GOTO</b> является команда <b>jmp short</b>.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.8>
|
||
9.8 Оператор разрыва break, BREAK.
|
||
</h2>
|
||
|
||
Оператор разрыва <b>break</b> прерывает выполнение операторов <b>do-while,
|
||
for, switch, while, loop, loopnz, LOOPNZ</b>. Он может содержаться
|
||
только в теле этих операторов. Управление передается оператору, следующему
|
||
за прерванным циклом.
|
||
|
||
Оператор <b>BREAK</b> аналогичен <b>break</b>, но при этом генерируется код на 1
|
||
байт короче. Размер сгенерированного кода от места где применяется <b>BREAK</b>
|
||
до конца цикла должен быть меньше 127 байт.
|
||
|
||
Примеры:
|
||
FOR (i=0; ; i++){
|
||
FOR(j=0; j < WIDTH; j++){
|
||
IF(i==5)BREAK;
|
||
}
|
||
IF(i==10)BREAK;
|
||
}
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.9>
|
||
9.9 Оператор продолжения continue, CONTINUE.
|
||
</h2>
|
||
|
||
Оператор продолжения <b>continue</b> передает управление на следующую
|
||
итерацию в циклах <b>do-while, for, while, loop, loopnz</b>. В циклах
|
||
<b>do-while, while, loop</b> следующая итерация начинается с вычисления
|
||
условного выражения. Для цикла <b>for</b> следующая итерация начинается с
|
||
вычисления выражения приращения, а затем происходит вычисление условного
|
||
выражения.
|
||
|
||
Оператор <b>CONTINUE</b> аналогичен <b>continue</b>, но при этом генерируется код на
|
||
1 байт короче. Размер сгенерированного кода от места где применяется
|
||
<b>CONTINUE</b> до начала итерации должен быть меньше 127 байт.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.10>
|
||
9.10 Логическое объединение условий.
|
||
</h2>
|
||
|
||
Существует возможность логического объединения сравнений в условиях
|
||
<b>IF и if</b>, циклах <b>do{}while, while{}, WHILE{}, for{} и FOR{}</b>.
|
||
Каждое сравнение при их логическом объединении должно быть заключено в
|
||
скобки. Объединять можно не более 32 сравнений.
|
||
|
||
В отличие от <b>C</b> в C-- анализ логических объединений происходит слева
|
||
направо и все лишние скобки будут восприняты компилятором как ошибочные.
|
||
Это несколько снижает гибкость и возможности применения этих объединений,
|
||
но такова традиция и философия, заложенная в C--.
|
||
|
||
Пример:
|
||
|
||
if ( (a>3) && (b>4) || (c<8) ){
|
||
|
||
Т.е. если произвести расшифровку этого условия, то получится следующее:
|
||
условие выполнится если a>3 и b>4 или a>3 и c<8.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.11>
|
||
9.11 Переход через циклы.
|
||
</h2>
|
||
|
||
Для операторов <b>BREAK, break, CONTINUE, continue</b> введена
|
||
поддержка числового параметра, определяющего, сколько циклов надо
|
||
пропустить, прежде чем будет выполнен этот оператор. Например, мы имеем три
|
||
вложенных цикла:
|
||
|
||
do{
|
||
loop(CX){
|
||
for(BX=0;BX<10;BX++){
|
||
break; //стандартный оператор
|
||
break 0; //break с параметром - пропустить 0 циклов
|
||
break 1; //break с параметром - пропустить 1 цикл
|
||
break 2; //break с параметром - пропустить 2 цикла
|
||
}
|
||
LABL0:
|
||
}
|
||
LABL1:
|
||
}while (DX!=0);
|
||
LABL2:
|
||
|
||
В третьем цикле находится группа различных вариантов оператора <b>break</b>.
|
||
Первым стоит стандартный оператор <b>break</b>, при выполнении которого
|
||
управление будет передаваться за пределы третьего цикла - на метку <b>LABL0</b>.
|
||
Вторым идет оператор <b>break 0</b>, при выполнении которого будет пропущено 0
|
||
циклов и управление будет передано опять же на метку <b>LABL0</b>. Таким
|
||
образом, запись <b>break и break 0</b> являются синонимами. Третьим идет
|
||
оператор <b>break 1</b>, при выполнении которого будет пропущен один цикл и
|
||
управление будет передано за пределы второго цикла на метку <b>LABL1</b>. Ну и
|
||
наконец, последним идет оператор <b>break 2</b>, при выполнении которого
|
||
компилятор пропустит два цикла и передаст управление за пределы третьего,
|
||
на метку <b>LABL2</b>. Метки в этом примере проставлены для удобства объяснения.
|
||
Ну и я надеюсь, Вам понятно, что значение параметра не может превышать
|
||
числа циклов находящихся перед текущим. Так для одиночного цикла этот
|
||
параметр может принимать максимальное и единственное значение - 0.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.12>
|
||
9.12 Инвертирование флага проверки условий.
|
||
</h2>
|
||
|
||
Инвертирование флага проверки условий в операциях сравнения <b>if/IF
|
||
for/FOR while/WHILE</b> происходит с помощью символа <b>! - not</b>.
|
||
|
||
Выражени
|
||
|
||
IF ( NOTCARRYFLAG )... и IF ( ! CARRYFLAG )...
|
||
IF ( proc() == 0 )... и IF ( ! proc() ) ...
|
||
|
||
являются синонимами.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.13>
|
||
9.13 Вычисление выражения, а затем проверка условия.
|
||
</h2>
|
||
|
||
В операциях сравнения в левом операнде теперь допустимо использовать
|
||
вычисления выражения с присваиванием и операции инкремента, декремента.
|
||
Например:
|
||
|
||
IF (i=a+2 != 0 )...
|
||
IF ( i++ )...
|
||
IF ( a-- )...
|
||
IF ( i+=4 == 0 )...
|
||
|
||
Во всех этих примерах сначала произойдет вычисление выражения в левой
|
||
части операции сравнения, а потом будет произведено сравнение результата с
|
||
правой частью выражения сравнения.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.14>
|
||
9.14 Проверка битов при операции сравнения.
|
||
</h2>
|
||
|
||
Если в левой части выражения сравнения написано: BX & 5, то при
|
||
вычислении выражения содержимое регистра BX будет изменено инструкцией
|
||
<b>and</b>. Но иногда возникает необходимость в проверке битов без изменения
|
||
содержимого регистра BX. Для этих целей надо использовать инструкцию
|
||
<b>test</b>. Как же указать компилятору, в каких ситуациях использовать
|
||
инструкцию <b>and</b>, а в каких <b>test</b>? В стандартных языках <b>C</b> для этого
|
||
используется механизм приоритетов - если выражение заключено в скобки, то
|
||
производится его вычисление, если нет, то производится проверка. Но C-- не
|
||
поддерживает приоритетов. Для разрешения этой проблемы в C-- решено
|
||
использовать непосредственно саму инструкцию <b>test</b>. Вот допустимые
|
||
варианты синтаксиса:
|
||
|
||
IF ( $test AX,5 )
|
||
IF ( ! $test AX,5)
|
||
IF ( asm test AX,5)
|
||
IF ( ! asm { test AX,5 } )
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.15>
|
||
9.15 Оператор перестановки.
|
||
</h2>
|
||
|
||
В C-- есть оператор, который не встречается в других языках, это
|
||
оператор перестановки. Оператор перестановки меняет местами содержимое двух
|
||
переменных. Символьное обозначение этого оператора ><. Переменные с обеих
|
||
сторон оператора перестановки должны иметь одинаковый размер, 8 бит и 8
|
||
бит, 16 бит и 16 бит, или 32 бита и 32 бита.
|
||
|
||
Вот некоторые примеры:
|
||
|
||
AX >< BX; // сохраняет значение BX в AX и значение AX в BX
|
||
CH >< BL; // меняет местами содержимое регистров CH и BL
|
||
dog >< cat; /* меняет местами значения переменной dog и переменной cat*/
|
||
counter >< CX; // меняет местами значения переменной counter
|
||
// и содержимое регистра CX
|
||
|
||
Если перестановка осуществляется между двумя 8-разрядными переменными в
|
||
памяти, будет разрушено содержимое регистра AL. Если перестановка - между
|
||
двумя 16-разрядными переменными в памяти, будет разрушено содержимое
|
||
регистра AX. Если перестановка - между двумя 32-разрядными переменными в
|
||
памяти, будет разрушено содержимое EAX. В любом другом случае, например,
|
||
между переменной в памяти и регистром, значения всех регистров будут
|
||
сохранены.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.16>
|
||
9.16 Оператор отрицания.
|
||
</h2>
|
||
|
||
C-- поддерживает быстрый синтаксис смены знака переменной - оператор
|
||
отрицания. Поставив <b>-</b> (знак минус) перед идентификатором переменной памяти
|
||
или регистра и <b>;</b> (точку с запятой) после идентификатора, вы смените знак
|
||
переменной памяти или регистра.
|
||
|
||
Вот некоторые примеры:
|
||
|
||
-AX; // результат тот же, что и при 'AX = -AX;' ,но быстрее.
|
||
-tree; // то же самое, что 'tree = -tree;' ,но быстрее.
|
||
-BH; // меняет знак BH.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.17>
|
||
9.17 Оператор инверсии.
|
||
</h2>
|
||
|
||
C-- поддерживает быстрый синтаксис выполнения логической инверсии
|
||
значения переменной - оператор инверсии. Поставив <b>!</b> (восклицательный знак)
|
||
перед идентификатором переменной памяти или регистром и <b>;</b> (точку с
|
||
запятой) после идентификатора, вы выполните логическую (выполнится
|
||
ассемблерная команда NOT) инверсию текущего значения переменной. Вот
|
||
некоторые примеры:
|
||
|
||
!AX; // то же самое, что ' AX ^ = 0xFFFF; ' но быстрее.
|
||
!node; // заменяет значение 'node' его логической инверсией.
|
||
!CL; // то же самое, что ' CL ^ = 0xFF ' но быстрее.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.18>
|
||
9.18 Специальные условные выражения.
|
||
</h2>
|
||
|
||
C-- поддерживает восемь специальных условных выражений:
|
||
|
||
CARRYFLAG
|
||
NOTCARRYFLAG
|
||
OVERFLOW
|
||
NOTOVERFLOW
|
||
ZEROFLAG
|
||
NOTZEROFLAG
|
||
MINUSFLAG
|
||
PLUSFLAG
|
||
|
||
Они могут использоваться вместо любых нормальных условных выражений.
|
||
Если Вы желаете, например, выполнить блок кода только если установлен флаг
|
||
переноса, Вам следует использовать следующую последовательность команд:
|
||
|
||
IF( CARRYFLAG )
|
||
{
|
||
// здесь вы чего-то делаете
|
||
}
|
||
|
||
Если Вы желаете непрерывно выполнять блок кода до тех пор, пока не
|
||
установится флаг переполнения, Вам следует использовать нечто подобное
|
||
следующему куску кода:
|
||
|
||
do {
|
||
// здесь вы опять чего-то делаете
|
||
} while( NOTOVERFLOW );
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.19>
|
||
9.19 Символ $ - вставляет текущий адрес программы.
|
||
</h2>
|
||
|
||
Символ <b>$</b>, кроме того, что является признаком последующей ассемблерной
|
||
инструкции, в языке C--, как и в языке Assembler может указывать текущий
|
||
адрес (смещение) компилируемой программы. Но в C-- он имел ограниченные
|
||
возможности. Он мог быть использован лишь как аргумент в операторах
|
||
<b>GOTO/goto</b> и ассемблерных инструкциях <b>DW/DD/JMP</b>.
|
||
|
||
Этот символ может находиться в любом месте вычисляемого числового
|
||
выражения и может быть применен в любом месте совместно с другими числовыми
|
||
выражениями.
|
||
|
||
Примеры применения:
|
||
|
||
DW #main-$ //записать расстояние от процедуры main до текущего места
|
||
GOTO $+2; //перейти по адресу на 2 больше, чем текущий адрес
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.20>
|
||
9.20 Ключевое слово static и оператор ::.
|
||
</h2>
|
||
|
||
Если перед объявлением глобальной переменной, структуры или процедуры
|
||
указать слово <b>static</b>, то эти переменная, структура или процедура будут
|
||
доступны только в том файле, в котором они были объявлены. Т.е. если Вы
|
||
включите этот файл в другой директивой <b>include</b>, то переменные объявленные
|
||
во включаемом файле со словом <b>static</b> не будут доступны в основном файле,
|
||
и Вы можете в основном файле объявить другие переменные с такими же
|
||
именами.
|
||
|
||
Если Вы примените слово <b>static</b> при объявлении локальной переменной в
|
||
процедуре, то память для этой переменной будет выделена не в стеке, а в
|
||
области данных процедуры. Но эта переменная будет доступна только внутри
|
||
процедуры, в которой она была объявлена. Применение <b>static</b> к локальным
|
||
переменным дает возможность сохранять значение переменной для следующего
|
||
входа в процедуру.
|
||
|
||
Слово <b>static</b> можно применять к любому глобальному объекту
|
||
(переменной, структуре, процедуре). Для локального использования это слово
|
||
можно применять только к переменным.
|
||
|
||
Если в Вашей программе есть глобальная и локальная переменная с
|
||
одинаковыми именами, то в процедуре, в которой объявлена эта локальная
|
||
переменная, Вы не имели доступа к одноименной глобальной переменной.
|
||
Применив перед именем переменной оператор <b>::</b>, Вы получите доступ к
|
||
глобальной переменной. Пример:
|
||
|
||
int var; //объявляем глобальную переменную
|
||
|
||
void proc()
|
||
int var; //объявляем локальную переменную с именем уже существующей
|
||
//глобальной переменной
|
||
{
|
||
(E)AX=var; //имеем доступ только к локальной переменной
|
||
(E)AX=::var; //а так можно получить доступ к глобальной переменной
|
||
}
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.21>
|
||
9.21 Оператор sizeof.
|
||
</h2>
|
||
|
||
Операция <b>sizeof</b> определяет размер памяти, который соответствует объекту
|
||
или типу. Операция sizeof имеет следующий вид:
|
||
|
||
sizeof (<имя типа>)
|
||
|
||
Результатом операции <b>sizeof</b> является размер памяти в байтах,
|
||
соответствующий заданному объекту или типу.
|
||
|
||
В C-- оператор <b>sizeof</b> можно применять к переменным, регистрам, типам
|
||
переменных, структурам, процедурам, текстовым строкам и файлам.
|
||
|
||
Если операция <b>sizeof</b> применяется к типу структуры, то результатом
|
||
является размер тега данной структуры.
|
||
|
||
Если операция <b>sizeof</b> применяется к текстовой строке, то результатом
|
||
операции является размер строки плюс завершающий нуль. Например:
|
||
|
||
sizeof ("Test")
|
||
|
||
результатом этой операции будет число 5. Если Вы напишите такую
|
||
конструкцию:
|
||
|
||
char a="Test";
|
||
|
||
sizeof(a)
|
||
|
||
то результатом будет 5 - размер памяти, отведенный для переменной a.
|
||
|
||
При использовании оператора <b>sizeof</b> с именем структуры вставляет
|
||
фактический размер памяти, занимаемый структурой. Это особенно важно, если
|
||
Вы объявили массив структур.
|
||
|
||
Оператор <b>sizeof</b> можно применять и к имени определенной ранее
|
||
процедуры. Результатом будет размер этой процедуры. Но для динамических
|
||
процедур всегда будет ноль.
|
||
|
||
Операцию <b>sizeof</b> можно применять и к файлам. Это бывает очень полезным
|
||
при использовании оператора <b>FROM</b>, но может применяться и в других случаях.
|
||
Пример применения оператора <b>sizeof</b> к файлам:
|
||
|
||
sizeof ( file "filename.dat" )
|
||
|
||
Результатом этой операции будет размер файла "filename.dat".
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=9.22>
|
||
9.22 Метки перехода.
|
||
</h2>
|
||
|
||
Метки перехода применяются для указания начальных точек участков кода,
|
||
используемых командами перехода встроенного ассемблера и операторами
|
||
<b>goto/GOTO</b>.
|
||
|
||
Имеются два типа меток перехода: глобальные и локальные. Глобальные
|
||
метки, как следует из названия, это метки, которые видимы из любого места в
|
||
программе. Локальные метки видны только в пределах своего процедурного
|
||
блока, и не определены за его пределами.
|
||
|
||
Метки определяются идентификатором, оканчивающимися двоеточием. Если
|
||
идентификатор содержит хотя бы один символ строчных букв (букв нижнего
|
||
регистра, маленьких букв), это глобальная метка перехода, в противном
|
||
случае, это локальная метка перехода.
|
||
|
||
Глобальные метки перехода не должны использоваться внутри динамических
|
||
процедур; там можно использовать только локальные метки. Это важно помнить,
|
||
поскольку, из-за применения такого средства как макрокоманды, динамическая
|
||
процедура может присутствовать в нескольких местах кода, что будет
|
||
означать, что метке соответствует больше чем один адрес.
|
||
|
||
Метки вне процедур фактически располагаются в области данных программы.
|
||
Если данные и код находятся в одном сегменте (а именно так организованна
|
||
программа, написанная на C--), то метки вне процедур становятся простым и
|
||
эффективным методом для получения расстояний между частями программы. В
|
||
качестве имен для меток вне процедур могут быть использованы уникальные
|
||
идентификаторы, в которых можно использовать большие, маленькие и смесь
|
||
больших и маленьких букв.
|
||
<a href="#contents9"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=10.1>
|
||
10. Ассемблер.
|
||
|
||
10.1 Поддержка команд ассемблера.
|
||
</h2>
|
||
|
||
Встроенный в C-- ассемблер поддерживает все инструкции 8088/8086,
|
||
80286, 80386, 80486, Pentium, Pentium II и Pentium III процессоров.
|
||
|
||
Все инструкции встроенного ассемблера должны начинаться с символа
|
||
доллара <b>$</b>. Поддерживается также ключевое слово <b>asm</b>, которое являясь
|
||
синонимом к символу доллара, еще и поддерживает объединение ассемблерных
|
||
инструкций в блоки.
|
||
<a href="#contents10"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=10.2>
|
||
10.2 Ключевое слово asm.
|
||
</h2>
|
||
|
||
Ключевое слово <b>asm</b> является синонимом к <b>$</b> - префикс ассемблерной
|
||
команды. После слова asm можно писать блок ассемблерных команд. Пример:
|
||
|
||
asm {
|
||
.
|
||
.
|
||
push AX
|
||
labl:
|
||
push BX
|
||
mov AX,0x1234
|
||
jmp short labl
|
||
.
|
||
.
|
||
.
|
||
}
|
||
|
||
Метки внутри блока ассемблерных команд допустимы.
|
||
<a href="#contents10"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=10.3>
|
||
10.3 Префикс dup - повторение инструкций DB/DW/DD.
|
||
</h2>
|
||
|
||
Для ассемблерных инструкции <b>DB, DW, DD</b> введена возможность использовать
|
||
префикс повторений <b>dup</b>. Применение этого префикса имеет следующий
|
||
синтаксис:
|
||
|
||
$DW NUMREP dup VALTOREP
|
||
|
||
NUMREP - число повторов инструкции DW.
|
||
VALTOREP - величина, которая будет повторена NUMREP раз.
|
||
|
||
В отличие от аналога этого префикса из ассемблера повторяемую величину
|
||
заключать в скобки нельзя.
|
||
<a href="#contents10"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=10.4>
|
||
10.4 Инструкции процессора Pentium III.
|
||
</h2>
|
||
|
||
В компилятор добавлена поддержка 19 новых инструкций MMX расширения
|
||
|
||
MASKMOVQ mmx,mmx
|
||
MOVNTQ m64,mmx
|
||
PAVGB mmx,mmx/m64
|
||
PAVGW mmx,mmx/m64
|
||
PEXTRW r32,mmx,i8
|
||
PINSRW mmx,r32/m16,i8
|
||
PMAXUB mmx,mmx/m64
|
||
PMAXSW mmx,mmx/m64
|
||
PMINUB mmx,mmx/m64
|
||
PMINSW mmx,mmx/m64
|
||
PMOVMSKB r32,mmx
|
||
PMULHUW mmx,mmx/m64
|
||
PREFETCHT0 mem
|
||
PREFETCHT1 mem
|
||
PREFETCHT2 mem
|
||
PREFETCHNTA mem
|
||
SFENCE
|
||
PSADBW mmx,mmx/m64
|
||
PSHUFW mmx,mmx/m64,i8
|
||
|
||
и 46 инструкций SSE расширения.
|
||
|
||
ADDPS xmm,m128/xmm
|
||
ADDSS xmm,xmm/m32
|
||
ANDNPS xmm,xmm/m128
|
||
ANDPS xmm,xmm/m128
|
||
COMISS xmm,xmm/m32
|
||
DIVPS xmm,m128/xmm
|
||
DIVSS xmm,xmm/m32
|
||
MAXPS xmm,m128/xmm
|
||
MAXSS xmm,xmm/m32
|
||
MINPS xmm,m128/xmm
|
||
MINSS xmm,xmm/m32
|
||
MULPS xmm,m128/xmm
|
||
MULSS xmm,xmm/m32
|
||
ORPS xmm,xmm/m128
|
||
RCPPS xmm,xmm/m128
|
||
RCPSS xmm,xmm/m32
|
||
RSQRTPS xmm,xmm/m128
|
||
RSQRTSS xmm,xmm/m32
|
||
SQRTPS xmm,m128/xmm
|
||
SQRTSS xmm,xmm/m32
|
||
SUBPS xmm,m128/xmm
|
||
SUBSS xmm,xmm/m32
|
||
UCOMISS xmm,xmm/m32
|
||
UNPCKHPS xmm,xmm/m128
|
||
UNPCKLPS xmm,xmm/m128
|
||
XORPS xmm,xmm/m128
|
||
CMPPS xmm,xmm/m128,i8
|
||
CMPSS xmm,xmm/m32,i8
|
||
SHUFPS xmm,xmm/m128,i8
|
||
CVTPI2PS xmm,m64/mmx
|
||
CVTSI2SS xmm,m32/r32
|
||
CVTPS2PI mmx,m128/xmm
|
||
CVTTPS2PI mmx,xmm/m128
|
||
CVTSS2SI r32,xmm/m128
|
||
CVTTSS2SI r32,xmm/m128
|
||
LDMXCSR m32
|
||
STMXCSR m32
|
||
MOVHLPS xmm,xmm
|
||
MOVLHPS xmm,xmm
|
||
MOVMSKPS r32,xmm
|
||
MOVNTPS m128,xmm
|
||
MOVAPS m128/xmm,xmm/m128
|
||
MOVSS xmm/m32,xmm/m32
|
||
MOVUPS xmm/m128,m128/xmm
|
||
MOVHPS xmm/m64,m64/xmm
|
||
MOVLPS xmm/m64,m64/xmm
|
||
|
||
Многие из этих инструкций могут использовать в качестве операнда
|
||
64-битные и 128-битные ячейки памяти. Компилятор C-- сейчас может работать
|
||
только с 32-битными переменными. Поэтому для инструкций использующих в
|
||
качестве операнда ячейки памяти размером больше 32-бит можно использовать
|
||
переменные любых типов. Компилятор не будет выдавать на это сообщений об
|
||
ошибке, будет использован адрес этой переменной, а сама инструкция будет
|
||
использовать нужное ей число битов памяти, начиная с адреса указанной
|
||
переменной. Например:
|
||
|
||
Для инструкции <b>movaps</b> один из операндов может быть 128-битной
|
||
ячейкой памяти. Для этой инструкции допустимы следующий синтаксис:
|
||
|
||
byte var8_128[16];
|
||
word var16_128[8];
|
||
dword var32_128[4];
|
||
|
||
void proc()
|
||
{
|
||
asm{
|
||
movaps var8_128,xmm0 //в массив из 16 байт будет записано содержимое XMM0
|
||
movaps xmm1,var16_128 //в XMM1 будет записано содержимое 8 слов
|
||
movaps var32_128,xmm1 //в массив из 4 двойных слов будет записано XMM1
|
||
}
|
||
}
|
||
<a href="#contents10"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.1>
|
||
11. Процедуры.
|
||
|
||
11.1 Типы процедур, функций и макрокоманд.
|
||
</h2>
|
||
|
||
Сейчас C-- поддерживает 4 типа вызова процедур: <b>cdecl, pascal, stdcall
|
||
и fastcall</b>. Вот краткие характеристики этих типов вызовов процедур:
|
||
|
||
<b><font color="Red">cdecl</font></b> Этот тип вызова процедур является по умолчанию для языка <b>С</b>. Он
|
||
характеризуется тем, что параметры процедуры передаются в порядке обратном
|
||
их записи. Очистка стека от параметров производится после завершения работы
|
||
процедуры. Этот способ вызова процедур очень удобен для процедур с
|
||
переменным числом параметров.
|
||
|
||
<b><font color="Red">pascal</font></b> Этот тип вызова предполагает, что параметры передаются в том
|
||
порядке, в котором они записаны в программе. Освобождение стека от
|
||
параметров производит сама вызываемая процедура. Этот тип вызова является
|
||
более компактным, чем <b>cdecl</b>.
|
||
|
||
<b><font color="Red">stdcall</font></b> Этот тип вызова является гибридом первых двух. Параметры
|
||
передаются процедуре в порядке обратном, тому в котором они записаны в
|
||
программе. Освобождение стека от параметров производится в самой вызываемой
|
||
процедуре.
|
||
|
||
<b><font color="Red">fastcall</font></b> Этот тип вызова процедур предполагает что передача параметров
|
||
процедуре производится через регистры, тем самым отпадает необходимость
|
||
освобождения стека от параметров. Для этого типа вызова процедуры
|
||
существуют ограничения по числу передаваемых параметров. Для C это три
|
||
параметра, а для C-- шесть. В C-- параметры передаются по умолчанию в
|
||
следующем порядке: <b>1-й - AX/EAX, 2-й - BX/EBX, 3 - CX/ECX, 4 - DX/EDX, 5 -
|
||
DI/EDI, 6 - SI/ESI</b>. Параметры типов char или byte могут передаваться в
|
||
количестве не более 4 или только в первых 4 регистрах: <b>1 - AL, 2 - BL, 3 -
|
||
CL, 4 - DL</b>. Этот порядок регистров может быть изменен, если явно указать
|
||
его либо при объявлении процедуры, либо при ее определении. Процедуры типа
|
||
fastcall иногда еще называют регистровыми.
|
||
|
||
В C-- по умолчанию, если имя процедуры написано большими буквами, то
|
||
считается, что эта процедура имеет тип вызова <b>fastcall</b>. Если же в имени
|
||
процедуры есть хотя бы одна маленькая буква, то по умолчанию считается, что
|
||
эта процедура имеет тип вызова <b>pascal</b>, за исключением программ
|
||
компилируемых с ключом <b>/w32 /w32c</b> или <b>/DLL</b>. В них по умолчанию применяется
|
||
тип вызова процедур <b>stdcall</b>. Если же Вы хотите изменить тип вызова процедур
|
||
из по умолчанию на любой другой, то эту процедуру надо обязательно объявить
|
||
с указанием типа желаемого вызова.
|
||
|
||
Объявление процедур введено для того, чтобы сообщать компилятору о
|
||
типе возврата из процедур, способе передачи параметров процедуре и их числе.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.2>
|
||
11.2 Стековые процедуры.
|
||
</h2>
|
||
|
||
Стековые процедуры по умолчанию объявляются при помощи идентификатора,
|
||
который содержит, по крайней мере, один символ строчных букв (букв нижнего
|
||
регистра, маленьких букв). Таким образом, стековые процедуры легко отличимы
|
||
от регистровых процедур, поскольку для имен регистровых процедур символы
|
||
строчных букв запрещены.
|
||
|
||
Параметры для стековых процедур, если они есть, могут иметь любой тип
|
||
<b>byte, char, word, int, dword, long</b> или <b>float</b>.
|
||
|
||
Параметры передаются в соответствии с правилами, принятыми для данного
|
||
типа процедур. Если процедура не имеет объявления, то компилятор не следит
|
||
за числом и типом передаваемых параметров. В этом случае у Вас появляется
|
||
свобода в их использовании, но Вы должны осознавать и последстви
|
||
неправильного их использования.
|
||
|
||
В списке параметров для каждого параметра указывается его тип.
|
||
Параметры одного типа, идущие подряд, разделяются запятыми. Формальные
|
||
параметры разного типа в объявлении функции разделяются символом <b>;</b>.
|
||
|
||
В следующем примере стековая процедура возвращает сумму всех своих
|
||
параметров (имеющих различные типы) как величину типа word:
|
||
|
||
word add_them_all (int a,b,c; byte d,e; word x,y)
|
||
{
|
||
return( a+b+c+d+e+x+y );
|
||
}
|
||
|
||
Ранее C-- делал вызовы стековых процедур лишь в стиле <b>pascal</b>.
|
||
Преимуществом этого способа вызова процедур является компактность и более
|
||
простой механизм генерации кода. К недостаткам, а соответственно и
|
||
преимуществам С-стиля, можно отнести жесткую привязанность паскалевских
|
||
процедур к числу и типу передаваемых параметров (попробуйте при вызове
|
||
процедуры в стиле <b>pascal</b> опустить один параметр и получите 100% зависание).
|
||
Напомню некоторые технические детали обоих типов вызовов процедур.
|
||
|
||
Кадр стека C-- для близких процедур стека в стиле pascal:
|
||
АДРЕС
|
||
...
|
||
BP + FFFE предпоследний байта локальных переменных
|
||
BP + FFFF последний байт локальных переменных
|
||
BP + 0000 Сохраненный BP
|
||
BP + 0002 RET адрес
|
||
BP + 0004 последнее слово передаваемых процедуре параметров (если они
|
||
есть)
|
||
BP + 0006 предпоследнее слово передаваемых процедуре параметров
|
||
...
|
||
BP + nnnn первое слово передаваемых процедуре параметров
|
||
|
||
Освобождение стека от переданных процедуре параметров происходит прямо
|
||
в самой процедуре командой <b>RET nnnn</b> - где nnnn является размером переданных
|
||
в стек параметров.
|
||
|
||
Кадр стека C-- для близких процедур стека в стиле си:
|
||
АДРЕС
|
||
...
|
||
BP + FFFE предпоследний байта локальных переменных
|
||
BP + FFFF последний байт локальных переменных
|
||
BP + 0000 Сохраненный BP
|
||
BP + 0002 RET адрес
|
||
BP + 0004 первое слово передаваемых процедуре параметров (если они
|
||
есть)
|
||
BP + 0006 второе слово передаваемых процедуре параметров
|
||
...
|
||
BP + nnnn последнее слово передаваемых процедуре параметров
|
||
|
||
Процедуры в стиле <b>С</b> заканчиваются командой <b>RET</b>. Освобождение стека от
|
||
параметров происходит в том месте откуда была вызвана процедура. Обычно это
|
||
делается командой <b>ADD SP,nnnn</b>. Т.е. компилятор может точно знать сколько и
|
||
каких параметров Вы передаете в данном случае процедуре и соответственно
|
||
освобождает стек после завершения процедуры. Это очень удобно для процедур,
|
||
которые могут обрабатывать переменное число параметров (например, процедуры
|
||
типа printf).
|
||
|
||
Объявление процедуры имеет следующий вид:
|
||
|
||
rettype modif procname();
|
||
|
||
Первым идет необязательный тип возврата из процедур. По умолчанию он
|
||
для 16-битных программ равен word, а для 32-битных dword. Затем должен идти
|
||
также необязательный модификатор. По умолчанию все стековые процедуры в C--
|
||
(за исключением режима компиляции программ под Windows, где по умолчанию
|
||
действует стиль вызова процедур <b>stdcall</b>) имеют стиль <b>pascal</b>. Далее идет им
|
||
процедуры со скобками, которые являются признаком того что Вы объявляете
|
||
процедуру, а не переменную. Завершает объявление символ точка с запятой.
|
||
|
||
При объявлении процедур в C-- прописывать параметры процедуры
|
||
необязательно (тогда компилятор не будет контролировать число и тип
|
||
передаваемых параметров), но если Вы их вставите, то включится механизм
|
||
контроля за числом и типом параметров.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.3>
|
||
11.3 Регистровые процедуры.
|
||
</h2>
|
||
|
||
Регистровые процедуры определяются, по умолчанию, при помощи
|
||
идентификатора, который не содержит символов строчных букв. Или же явным
|
||
указанием что это регистровая процедура с помощью ключевого слова <b>fastcall</b>.
|
||
|
||
Как уже было сказано, параметры (если они есть) для регистровой
|
||
процедуры передаются через регистры. Регистровые процедуры могут иметь не
|
||
более 6 параметров. Если параметры имеют тип int или word, регистры по
|
||
умолчанию используются в следующем порядке: <b>AX, BX, CX, DX, DI, и SI</b>.
|
||
Первые четыре параметра могут также иметь тип <b>char</b> или <b>byte</b>, в этом случае
|
||
задействуются регистры <b>AL, BL, CL и DL</b> соответственно. Любой из шести
|
||
параметров может иметь тип <b>long, dword</b> или <b>float</b>, тогда для него
|
||
используется регистр <b>EAX, EBX, ECX, EDX, EDI</b>, или <b>ESI</b>.
|
||
|
||
В следующем примере регистровая процедура с именем TOGETHER возвращает
|
||
значение типа word как результат умножения первого параметра, имеющего тип
|
||
word, на второй параметр того же типа:
|
||
|
||
word TOGETHER() /* AX = первый параметр, BX = второй параметр */
|
||
{
|
||
return (AX * BX);
|
||
}
|
||
|
||
В следующем примере регистровая процедура с именем SHOW_NUM, которая не
|
||
возвращает никакого значения, зато выводит на экран первый параметр
|
||
(имеющий тип int), затем разделительный знак в виде двоеточия <b>:</b>, а затем
|
||
второй параметр (имеющий тип byte) :
|
||
|
||
void SHOW_NUM () /* AX = первое число, BL = второе число */
|
||
{
|
||
$ PUSH BX
|
||
WRITEINT (int AX);
|
||
WRITE (':');
|
||
$ POP BX
|
||
WRITEWORD (BL);
|
||
}
|
||
|
||
Но если в процедуре сделать объявление порядка и типов используемых
|
||
регистров, то возможно произвольное использование регистров. Более подробно
|
||
об этом можно почитать в разделе об объявлениях параметров в регистровых
|
||
процедурах.
|
||
|
||
Для того, чтобы использовать регистровую процедуру как макрокоманду,
|
||
она должна быть объявлена как динамическая процедура. Динамические
|
||
процедуры описаны в следующем подразделе.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.4>
|
||
11.4 Динамические процедуры.
|
||
</h2>
|
||
|
||
Динамические процедуры - процедуры, которые определены, но вставляются
|
||
в код программы, только если есть вызов. Динамические процедуры могут
|
||
использоваться как макрокоманды.
|
||
|
||
Определение динамической процедуры начинается с символа двоеточия ':'.
|
||
|
||
Пример динамической процедуры стека:
|
||
|
||
: void setvideomode (byte mode)
|
||
{
|
||
AL = mode;
|
||
AH = 0;
|
||
$ INT 0x10
|
||
}
|
||
|
||
Пример динамической регистровой процедуры:
|
||
|
||
: int ABS () /* AX = число, абсолютное значение которого ищется*/
|
||
{
|
||
IF (int AX < 0)
|
||
-AX;
|
||
}
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.4.1>
|
||
11.4.1 Установка динамической процедуры в определенное место программы.
|
||
</h2>
|
||
|
||
Динамические процедуры, если они не используются как макросы и если
|
||
они были востребованы в программе, вставляются в код программы в самом
|
||
конце компиляции. В каком точно месте Вашей программы они окажутся узнать
|
||
невозможно. Если же Вам необходимо, чтобы какая-то динамическая процедура
|
||
находилась в конкретном месте программы, то это можно сделать таким
|
||
образом:
|
||
|
||
:void proc ( int par1, par2)
|
||
{
|
||
...
|
||
}
|
||
|
||
Мы имеем динамическую процедуру, код которой был бы расположен ранее
|
||
кода обычной процедуры нашей программы. Для этого перед определением этой
|
||
процедуры надо написать такую строку:
|
||
|
||
@ void proc ();
|
||
|
||
В итоге динамическая процедура будет вставлена в код программы не в
|
||
конце ее, как обычно, а в месте, где будет расположена эта строка. Если
|
||
динамическая процедура имеет параметры, то прописывать эти параметры
|
||
необязательно.
|
||
|
||
В компиляторе есть еще более мощное средство, позволяющее все
|
||
динамические объекты ( процедуры, переменные, структуры ) расположить в
|
||
указанном месте, а не в конце программы, как обычно. Это директива
|
||
<b>#setdinproc</b>. Встретив эту директиву, компилятор немедленно расположит все
|
||
известные ему на этот момент динамические объекты в месте объявления этой
|
||
директивы. Последующие динамические объекты будут располагаться как
|
||
обычно, в конце программы, если конечно, не будет повторно применена
|
||
директива <b>#setdinproc</b>.
|
||
|
||
Это может быть применено и быть полезным при создании резидентных
|
||
программ (TSR) и драйверов устройств.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.5>
|
||
11.5 inline-процедуры.
|
||
</h2>
|
||
|
||
inline-процедурами могут быть динамические процедуры, которые можно
|
||
использовать как макросы. Но в отличие от макросов, inline-процедуры, при
|
||
включенной оптимизации на скорость, автоматически вставляются в код, а при
|
||
оптимизации кода на размер, делается вызов их, как динамических процедур.
|
||
|
||
Но иногда бывает нужно при включенной оптимизации на размер кода, чтобы
|
||
процедуры вставлялись в код, а не делался их вызов. Для этих целей введена
|
||
директива <b>#inline TRUE</b>. Этой же директивой ( <b>#inline FALSE</b> ), можно при
|
||
оптимизации на скорость делать вызовы процедур, вместо их вставки.
|
||
|
||
Важно помнить, что статус директивы <b>#inline</b> автоматически меняется при
|
||
смене режима оптимизации. При установке оптимизации на скорость статус
|
||
директивы <b>#inline</b> устанавливается в <b>TRUE</b>, а при смене режима оптимизации по
|
||
размеру кода, устанавливается в <b>FALSE</b>. Поэтому применяйте директиву <b>#inline</b>
|
||
лишь после смены режима оптимизации.
|
||
|
||
Директивы меняющие режим оптимизации <b>#codesize, #speed</b> и директива
|
||
<b>#inline</b>, объявленные внутри процедуры распространяются только на оставшуюся
|
||
часть процедуры, т.е. они становятся локальными. Для того чтобы изменения
|
||
были глобальными эти директивы надо объявлять вне тела процедуры.
|
||
|
||
Для того чтобы определить inline-процедуру, надо в первой строке с
|
||
именем процедуры вместо символа динамической процедуры <b>(:)</b> написать
|
||
ключевое слово <b>inline</b>. Пример определения inline-процедуры:
|
||
|
||
inline int fastcall abs(AX)
|
||
{
|
||
IF ( int AX < 0 ) -AX ;
|
||
}
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.5.1>
|
||
11.5.1 Другое применение inline.
|
||
</h2>
|
||
|
||
Ключевое слово <b>inline</b> имеет в процедурах и другое применение. Если
|
||
это слово расположено перед началом блока процедуры, то для такой
|
||
процедуры не создается кадр стека и не генерируется завершающий процедуру
|
||
<b>ret</b>. Пример:
|
||
|
||
void PROC ()
|
||
inline
|
||
{
|
||
...
|
||
}
|
||
|
||
Такие процедуры не должны содержать локальных переменных. Если
|
||
процедура является регистровой (тип <b>fastcall</b>), то с передачей ей
|
||
параметров нет проблем. Если же процедура является стековой, то передать
|
||
в такую процедуру параметры Вы можете, но воспользоваться этими
|
||
параметрами используя их имена, Вы уже не сможете. Это происходит потому,
|
||
что в этих процедурах кадр стека не формируется. Пример:
|
||
|
||
void proc (int par1, par2)
|
||
inline
|
||
{
|
||
AX=par1; /* компилятор обратится с параметру 'par1' через регистр BP.
|
||
Но так как кадр стека не был создан, при выполнении этого
|
||
кода программа будет работать не правильно. */
|
||
...
|
||
}
|
||
|
||
Встретив такое определение процедуры, компилятор выдаст предупреждение
|
||
о том, что в таких процедурах использовать локальные и параметрические
|
||
переменные нельзя.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.6>
|
||
11.6 Процедуры обработки прерываний.
|
||
</h2>
|
||
|
||
Процедуры обработки прерываний определяются следующим способом:
|
||
|
||
interrupt procedure_name ()
|
||
{
|
||
// put code here (здесь должен быть код обработки)
|
||
}
|
||
|
||
Процедуры обработки прерываний не сохраняют никаких регистров
|
||
автоматически, и никакие регистры сами по себе не загружаются перед
|
||
передачей управления обработчику прерывания, следовательно, на Вашей
|
||
совести сохранение значений регистров в стеке и последующий их возврат, а
|
||
также загрузка регистра DS нужным значением.
|
||
|
||
Вот пример обработчика прерывания, который сохраняет значения всех
|
||
регистров и загружает регистр DS:
|
||
|
||
interrupt safe_handle ()
|
||
{
|
||
$ PUSH DS
|
||
$ PUSH ES
|
||
$ PUSHA // для выполнения этой команды нужен процессор не хуже 80286
|
||
DS = CS; // здесь DS загружается для работы с моделью памяти типа tiny
|
||
|
||
|
||
/* do your thing here (здесь вы делаете свою обработку)*/
|
||
|
||
$ POPA // для выполнения этой команды нужен процессор не хуже 80286
|
||
$ POP ES
|
||
$ POP DS
|
||
}
|
||
|
||
При завершении процедуры прерывания будет автоматически сгенерирована
|
||
инструкция выхода из обработчика прерывания - IRET.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.7>
|
||
11.7 Замена return на goto.
|
||
</h2>
|
||
|
||
В некоторых ситуациях, при компиляции программы, оператор <b>return</b>
|
||
будет заменяться на <b>goto</b>. Это происходит при разрешенной оптимизации по
|
||
размеру кода для операторов <b>return</b>, которые расположены внутри процедуры
|
||
и, естественно, если размер кода для выполнения <b>return</b> больше, чем размер
|
||
кода для реализации <b>goto</b>. Для динамических процедур, которые используются
|
||
как макросы, такая замена будет производится всегда. Оператор <b>goto</b> будет
|
||
выполнен на конец процедуры, там, где будет располагаться единственный
|
||
выход из процедуры. В динамических процедурах, используемых в качестве
|
||
макросов, <b>return</b> в конце процедуры будет пропущен компилятором.
|
||
|
||
Таким образом, снято последнее ограничение на использование
|
||
динамических процедур в качестве макросов. Любая динамическая процедура
|
||
может быть использована как макрос.
|
||
|
||
Для оператора <b>goto</b> существует его более короткий аналог - <b>GOTO</b>.
|
||
Для получения более компактного кода для оператора <b>return</b> введен также
|
||
более короткий оператор <b>RETURN</b>. Его можно использовать, если от места
|
||
его применения до конца процедуры находится не более 128 байт. Если Вы
|
||
будете использовать <b>RETURN</b> на большем расстоянии до конца процедуры, то
|
||
компилятор выдаст сообщение об ошибке. При использовании <b>return</b> на
|
||
расстоянии меньше 128 байт до конца кода, компилятор выдаст вам
|
||
предупреждение о возможном использовании <b>RETURN</b>.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.8>
|
||
11.8 Возвращаемые значения.
|
||
</h2>
|
||
|
||
Возвращаемые из функций значения располагаются в регистрах. В таблице
|
||
показано, какой регистр используется для каждого из возвращаемых типов:
|
||
|
||
--------------------------------------------
|
||
| возвращаемый тип | используемый регистр |
|
||
--------------------------------------------
|
||
| byte | AL |
|
||
| word | AX |
|
||
| dword | EAX |
|
||
| char | AL |
|
||
| int | AX |
|
||
| long | EAX |
|
||
| float | EAX |
|
||
--------------------------------------------
|
||
|
||
Самый простой способ вернуть значение из функции состоит в том, чтобы
|
||
использовать команду return(), но вместо этого можно напрямую загрузить
|
||
возвращаемое значение в соответствующий регистр. Например, следующие две
|
||
функции возвращают одно и то же значение:
|
||
|
||
byte proc_one ()
|
||
{
|
||
return (42);
|
||
}
|
||
|
||
byte proc_two ()
|
||
{
|
||
AL = 42;
|
||
}
|
||
|
||
Многие DOS функции 0x21 прерывания в качестве индикатора успешного
|
||
выполнения используют установку или сброс carry флага. Использовать флаги
|
||
процессора при возврате из процедур можно и в других случаях, когда надо
|
||
иметь статус успешного или не успешного выполнения процедуры. Это позволит
|
||
более полно использовать возможности процессора и соответственно уменьшит
|
||
размер кода и повысит быстродействие программы.
|
||
|
||
Наряду с флагами, при возврате из процедур, по прежнему остается
|
||
возврат различных типов и через регистр <b>AL/AX/EAX</b>. Если для процедуры
|
||
объявлено, что она имеет тип возврата <b>int и CARRYFLAG</b>, то при использовании
|
||
такой процедуры в операциях сравнения <b>IF, WHILE...</b> будет делаться проверка
|
||
carry флага, а не сравнение регистра AX. Пример использования возврата
|
||
флагов из процедур:
|
||
|
||
int CARRYFLAG FOPEN(); // объявление процедуры
|
||
|
||
void proc()
|
||
{
|
||
IF ( FOPEN(name,0) ) Error ( "Not open file" );
|
||
}
|
||
|
||
Варианты допустимого синтаксиса для использования возврата флага:
|
||
|
||
IF ( ! FOPEN() )...
|
||
IF ( @ FOPEN() )...
|
||
IF ( ! @ FOPEN() )...
|
||
IF ( handl = FOPEN() )...
|
||
IF ( handl = @ FOPEN() )...
|
||
IF ( ! handl = FOPEN() )...
|
||
IF ( ! handl = @ FOPEN() )...
|
||
|
||
А вот варианты, в которых, несмотря на то, что для процедуры объявлен
|
||
возврат флага, будет производиться сравнение регистра AX:
|
||
|
||
IF ( FOPEN() == 5 )... // производится сравнение
|
||
IF ( FOPEN() + 2 )... // результат процедуры подвергается дальнейшему
|
||
// вычислению, в результате которого флаги будут
|
||
// изменены.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.9>
|
||
11.9 Объявление параметров в регистровых процедурах.
|
||
</h2>
|
||
|
||
Ранее каждому параметру регистровой процедуры соответствовал строго
|
||
определенный регистр. Например, для переменных типа int или word первый
|
||
параметр передавался через регистр AX, 2-й - BX, 3-й - CX, 4-й - DX, 5-й -
|
||
DI, 6-й - SI. Поэтому, если Вам было необходимо передать только один
|
||
параметр через регистр SI, то приходилось перед ним писать пять запятых.
|
||
Вот как, например, выглядит вызов процедуры STRCPY:
|
||
|
||
void main ()
|
||
{
|
||
STRCPY ( , , , , #dest, #sourc ) ;
|
||
}
|
||
|
||
Теперь регистры могут располагаться при передаче параметров
|
||
произвольным образом. Надо только объявить компилятору о том, какой регистр
|
||
закреплен за каким параметром данной процедуры. После такого объявления
|
||
компилятор будет сам следить за тем, через какой регистр передавать
|
||
параметр процедуре, его размерностью и числом передаваемых параметров. Вот
|
||
как будет выглядеть объявление и использование процедуры STRCPY:
|
||
|
||
void STRCPY ( DI, SI ) ; //это объявление процедуры
|
||
|
||
void main ()
|
||
{
|
||
STRCPY ( #dest, #sourc ) ; //а это вызов процедуры
|
||
}
|
||
|
||
Можно не делать объявления процедуры, а указать расположение регистров
|
||
в заголовке процедуры. Но тогда такая процедура должна вызываться только
|
||
после ее определения. Вот пример процедуры выводящей на экран несколько
|
||
одинаковых символов:
|
||
|
||
void PUTNCHAR(AL,CX,BL,BH)
|
||
/* 1 параметр в AL - код символа, который будет выведен
|
||
2 параметр в CX - число выводимых символов
|
||
3 параметр в BL - цветовой атрибут
|
||
4 параметр в BH - номер видеостраницы
|
||
*/
|
||
{
|
||
AH=9;
|
||
$INT 0x10
|
||
}
|
||
|
||
При объявлении регистровой процедуры можно также указывать какой тип
|
||
переменной ожидает процедура (знаковый/без знаковый или вещественный). По
|
||
умолчанию считается без знаковый тип. Однако знаковый тип указывать есть
|
||
смысл только если параметр передается через регистр <b>AL/AX/EAX</b>. Через другие
|
||
регистры переменная всегда передается как без знаковая. Пример объявления
|
||
регистровой процедуры с указанием типов:
|
||
|
||
int fastcall Exampl( word CX, int AX, DX, float ESI ) ;
|
||
| | | | | | |
|
||
| | | | | | |---- 4-й парам. имеет тип float и
|
||
| | | | | | перед. через регистр ESI.
|
||
| | | | | |-------- 3-й парам. имеет по умолч.
|
||
| | | | | тип word и перед. через DX.
|
||
| | | | |------------ 2-й парам. имеет тип int и
|
||
| | | | передается через регистр AX.
|
||
| | | |---------------------- 1-й парам. имеет тип word и
|
||
| | | передается через регистр CX.
|
||
| | |------------------------------- Имя объявляемой процедуры.
|
||
| |---------------------------------------- Модификатор, указывающий, что
|
||
| эта проц. явл. регистровой.
|
||
|--------------------------------------------- Процедура возвращает перемен.
|
||
типа int.
|
||
|
||
Если Вы сделали объявление регистров процедуры, то компилятор будет
|
||
строго следить за количеством указанных параметров при вызове этой
|
||
процедуры и выдавать сообщения об ошибке, если их будет меньше или больше.
|
||
С одной стороны это хорошо - есть контроль за тем, что Вы ничего не забыли
|
||
или не добавили лишнего при вызове процедуры. С другой стороны иногда
|
||
бывают необязательные параметры, а их теперь придется прописывать. Но если
|
||
Вы при вызове процедуры не укажете ни одного параметра, то компилятор не
|
||
будет Вам выдавать сообщение об ошибке. Это дает Вам возможность
|
||
проинициализировать регистры, через которые Вы передаете параметры, вне
|
||
вызова процедуры. Но если Вы укажете, хоть один параметр, то Вам придется
|
||
указывать и остальные, иначе компилятор будет считать, что Вы их случайно
|
||
пропустили и выдаст сообщение об ошибке.
|
||
|
||
Если Вы не объявили регистры ни при объявлении регистровой процедуры,
|
||
ни в заголовке самой процедуры, то компилятор будет считать, что параметры
|
||
в эту процедуру передаются старым способом. Таким образом, достигается
|
||
полная совместимость с предыдущими версиями компилятора.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.10>
|
||
11.10 Объявление параметров в стековых процедурах.
|
||
</h2>
|
||
|
||
Как известно, ранее в C-- контроль за числом и типом передаваемых
|
||
процедуре параметров возлагался на программиста. Поэтому возникла непростая
|
||
задача, совместить одновременно отсутствие контроля за параметрами (для
|
||
совместимости с предыдущими версиями) и ее наличие. В результате
|
||
компромиссов появился вариант немного отличающийся от традиционно принятого
|
||
в языках C.
|
||
|
||
Главное отличие - это то, что параметры, определяемые при определении
|
||
процедуры, не будут восприниматься компилятором для контроля за ними. Во
|
||
всех языках C допускается совмещение прототипа процедуры и ее объявления.
|
||
В C-- для того, чтобы включился контроль за параметрами стековой процедуры,
|
||
надо эту процедуру обязательно объявить. Но не всякое объявление процедуры
|
||
будет сигналом компилятору о включении контроля за параметрами этой
|
||
процедуры. Если при объявлении в круглых скобках ничего не будет, то
|
||
компилятор не будет отслеживать параметры, передаваемые этой процедуре. В
|
||
C++ такое объявление означает, что процедуре не передаются никакие
|
||
параметры. В C-- для этого надо при объявлении процедуры в круглых скобках
|
||
обязательно написать void. Например:
|
||
|
||
int proc ( void ) ;
|
||
|
||
Встретив такое объявление процедуры, компилятор будет следить за тем,
|
||
чтобы этой процедуре не были переданы параметры.
|
||
|
||
При объявлении процедуры имена параметров можно опускать. Как известно,
|
||
в C-- параметры процедуры одного типа записываются через запятую. Для смены
|
||
типа используют точку с запятой. При объявлении смену типа можно
|
||
производить и после запятой:
|
||
|
||
void ptoc ( int a, b, c; word d );
|
||
void proc ( int, int, int, word );
|
||
void proc ( int, int, int; word );
|
||
|
||
Все эти примеры объявлений являются идентичными и допустимыми.
|
||
|
||
Для контроля за процедурами с переменным числом параметров был введен
|
||
новый для C-- элемент синтаксиса - многоточие или его еще называют эллипс.
|
||
Вот как будет выглядеть объявление процедуры printf:
|
||
|
||
void cdecl printf ( word, ... );
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.11>
|
||
11.11 Использование макрокоманд.
|
||
</h2>
|
||
|
||
Теперь любая динамическая процедура может быть использована как макрос.
|
||
Если перед вызовом динамической процедуры поставить символ <b>@</b>, то код этой
|
||
процедуры будет вставлен, а не вызван инструкцией CALL.
|
||
|
||
При использовании стековых динамических процедур в качестве макросов
|
||
очистка стека от переданных параметров производится ассемблерной
|
||
инструкцией <b>ADD SP,SIZE_PARAMETRS</b> сразу после окончания кода вставленного
|
||
макроса. Поэтому, если эта процедура использовала флаги в качестве
|
||
возврата, то они будут разрушены.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.12>
|
||
11.12 Передача параметров в стековые процедуры через регистры.
|
||
</h2>
|
||
|
||
При передаче параметров через регистры, чаще всего получается более
|
||
компактный и быстрый код. Но содержимое регистров может быть легко
|
||
разрушено. Если в Вашей процедуре, какой-то из параметров используется
|
||
однократно для того, чтобы в начале процедуры инициализировать какой-то
|
||
регистр, то Вы можете передать это значение в процедуру сразу через
|
||
регистр, минуя стадию засовывания и извлечения содержимого в стек. Пример:
|
||
|
||
int proc (int param1, param2, param3)
|
||
{
|
||
(E)BX = param3;
|
||
(E)BX.TEG_STRUCT.var = proc2 (param1,papra2);
|
||
proc3 (param1,param2);
|
||
}
|
||
|
||
В этом примере параметр param3 используется лишь для того, чтобы
|
||
инициализировать регистр (E)BX, поэтому его можно сразу передать через
|
||
регистр:
|
||
|
||
int proc (int param1, param2, (E)BX)
|
||
{
|
||
(E)BX.TEG_STRUCT.var = proc2 (param1,papra2);
|
||
proc3 (param1,param2);
|
||
}
|
||
|
||
Как Вы видите, процедура немного упростилась.
|
||
|
||
В принципе, порядок расположения стековых и регистровых параметров не
|
||
принципиален. Но надо помнить, что содержимое регистров может быть легко
|
||
разрушено, и поэтому лучше всего регистровые параметры инициализировать
|
||
лишь после того, как были засунуты в стек все стековые параметры. Для
|
||
процедур типа <b>pascal</b> регистровые параметры лучше располагать после
|
||
стековых параметров. Для процедур типа <b>cdecl и stdcall</b> сначала лучше
|
||
располагать регистровые параметры.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.13>
|
||
11.13 Вызов процедур с адресом в регистре.
|
||
</h2>
|
||
|
||
В C-- допустимо делать вызов процедуры, адрес которой находится в
|
||
регистре. Параметры для такого вызова передаются только через стек. Тип
|
||
вызова процедуры для программ под Windows <b>stdcall</b>, для остальных <b>pascal</b>.
|
||
Адрес процедуры для 32-битных программ должен находится в 32-битном
|
||
регистре, а для 16-битных программ в 16-битном регистре. Считается, что
|
||
такой вызов имеет возврат типа <b>unsigned int</b>. Пример:
|
||
|
||
BX = # proc;
|
||
BX (a);
|
||
IF ( BX(b) == 0 ) AX=2;
|
||
|
||
Вы получите следующий код:
|
||
|
||
test.c-- 8: BX=#proc;
|
||
0104 BB1A01 mov bx,11Ah
|
||
|
||
test.c-- 9: BX(a);
|
||
0107 FF76FC push word ptr [bp-4]
|
||
010A FFD3 call near bx
|
||
|
||
test.c-- 10: IF (BX(b) == 0)AX=2;
|
||
010C FF76FE push word ptr [bp-2]
|
||
010F FFD3 call near bx
|
||
0111 85C0 test ax,ax
|
||
0113 7503 jne 118h
|
||
0115 B80200 mov ax,2
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.14>
|
||
11.14 Встроенные в компилятор процедуры.
|
||
</h2>
|
||
|
||
Для некоторых процедур Вы не найдете их исходные тексты в библиотеках
|
||
компилятора. Код этих процедур генерирует компилятор. Вот список этих
|
||
процедур:
|
||
|
||
ABORT Прекращение выполнения программы
|
||
atan Вычислить арктангенс числа
|
||
atan2 Вычислить арктангенс числа
|
||
ATEXIT Зарегистрировать функцию выполняющуюся при выходе.
|
||
cos Возвращает косинус угла
|
||
EXIT Закончить программу с кодом ошибки
|
||
exp Возвращает экспоненту числа
|
||
inp/inportb Считать один байт из порта
|
||
inport Считать слово из порта
|
||
inportd Считать двойное слово из порта
|
||
fabs Возвращает абсолютное значение числа
|
||
log Вычисляет натуральный логарифм числа
|
||
log10 Вычисляет десятичный логарифм числа
|
||
outp/outportb Записать один байт в порт
|
||
outport Записать слово в порт
|
||
outportd Записать двойное слово в порт
|
||
sin Возвращает синус угла
|
||
sqrt Извлечь квадратный корень через FPU.
|
||
tan Возвращает тангенс угла
|
||
|
||
Размещение этих процедур непосредственно в компиляторе, связано с тем,
|
||
что в настоящий момент компилятор может таким образом генерировать более
|
||
эффективный код, чем если бы эти процедуры располагались в библиотеках.
|
||
В будущем, по мере развития компилятора, эти процедуры постепенно будут
|
||
выносится из компилятора в библиотеки.
|
||
|
||
Но ничто не мешает Вам уже сейчас написать свои одноименные
|
||
библиотечные процедуры. Встретив определение такой процедуры, компилятор не
|
||
будет выдавать никаких сообщение, он просто будет применять Ваш вариант
|
||
процедуры.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.14.1>
|
||
11.14.1 Процедуры ABORT, ATEXIT и EXIT.
|
||
</h2>
|
||
|
||
Процедуры <b>ABORT и EXIT</b> связаны с работой директивы <b>#atexit</b> и
|
||
процедурой <b>ATEXIT</b>. Наиболее оптимальную их реализацию и взаимную
|
||
интеграцию может сделать только компилятор. Именно поэтому эти процедуры
|
||
поддерживаются компилятором.
|
||
|
||
Процедура <b>ATEXIT</b> - регистровая процедура, которая регистрирует
|
||
функцию, адрес которой передается ей в качестве параметра, т.е. через
|
||
регистр (E)AX, как функцию завершения программы. При успешной регистрации
|
||
<b>ATEXIT</b> возвращает 0. Всего можно зарегистрировать до 16 функций.
|
||
|
||
Завершающие функции не должны иметь параметров и возврата. Эти
|
||
функции будут выполняться в порядке обратном очередности регистрации в
|
||
случае, если Вы будете завершать работу программы через вызовы процедур
|
||
<b>ABORT</b> или <b>EXIT</b> или закончится работа процедуры <b>main</b>. Если Вы
|
||
завершите работу программы вызовом процедуры <b>ExitProcess</b> под Windows или
|
||
вызовом <b>AH=0x4C; $int 0x21</b> под DOS, выход из программы произойдет без
|
||
запуска зарегистрированных функций.
|
||
|
||
Процедура <b>ABORT и EXIT</b>, если не включена директива <b>#atexit</b> делают
|
||
вызов процедуры <b>ExitProcess</b> под Windows и вызов <b>AH=0x4C; $int 0x21</b> под
|
||
DOS. Процедуре <b>ABORT</b> не передаются никакие параметры, и она завершает
|
||
работу программы с кодом возврата 0. Процедуре <b>EXIT</b> передается в
|
||
качестве параметра код возврата, с которым она и завершает работу
|
||
программы.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.14.2>
|
||
11.14.2 Процедуры inp/inportb, inport, inportd, outp/outportb, outport и
|
||
outportd
|
||
</h2>
|
||
|
||
Эти процедуры всегда вставляются в код как макросы, т.е. для этих
|
||
процедур никогда не генерируется вызов процедуры. В зависимости от
|
||
значения порта, с которым работают эти процедуры, генерируется разный
|
||
код. Все это позволяет получать более компактный код.
|
||
|
||
Процедуры чтения из порта имеют такой прототип:
|
||
|
||
byte inp ( word port );
|
||
word inport ( word port );
|
||
dword inportd ( word port );
|
||
|
||
Процедуры записи в порт имеют такой прототип:
|
||
|
||
void outp ( byte val; word port );
|
||
void outport ( word val; word port );
|
||
void outportd ( dword val; word port );
|
||
|
||
Имена процедур inp и inportb, также как и имена outp и outportb
|
||
являются синонимами.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.14.3>
|
||
11.14.3 Процедуры для работы с вещественными числами.
|
||
</h2>
|
||
|
||
Эти процедуры реализуются компилятором и всегда вставляются в код как
|
||
макросы, т.е. для них никогда не генерируется вызов процедуры. Кроме
|
||
этого, если параметром одной процедуры является вызов другой, то
|
||
результат работы второй процедуры остается в стеке FPU, а первая
|
||
процедура использует этот результат непосредственно из стека. Таким
|
||
образом получаются более компактный код. Вот вымышленный пример:
|
||
|
||
test.c-- 7: f = sin( sqrt(1) );
|
||
0100 D9061C01 fld [11Ch]
|
||
0104 D9FA fsqrt
|
||
0106 D9FE fsin
|
||
0108 D91E2001 fstp [120h]
|
||
010C 9B fwait
|
||
|
||
Эти процедуры имеют следующий прототип:
|
||
|
||
float atan ( float val );
|
||
float atan ( float val, val2 );
|
||
float cos ( float val );
|
||
float exp ( float val );
|
||
float fabs ( float val );
|
||
float log ( float val );
|
||
float log10 ( float val );
|
||
float sin ( float val );
|
||
float sqrt ( float val );
|
||
float tan ( float val );
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.15.1>
|
||
11.15 Классы.
|
||
|
||
11.15.1 Объявление процедур в структурах.
|
||
</h2>
|
||
|
||
С введение поддержки объявления процедур в структурах, структура
|
||
становится подобной классу в C++. Т.е. такая процедура становится методом
|
||
класса. Пример:
|
||
|
||
struct Point // объявление класса
|
||
{
|
||
int x; // элементы данных
|
||
int y; // класса типа Point
|
||
void SetX(int); // объявление методов
|
||
void SetY(int); // класса Point
|
||
};
|
||
|
||
void Point::SetX(int _x) //определение процедуры класса Point
|
||
{
|
||
IF((_x>=0)&&(_x<=MAX_X)) x=_x;
|
||
// переменные x, y являются членами этого класса и поэтому доступ к ним из
|
||
// процедур этого же класса осуществляется напрямую.
|
||
}
|
||
|
||
void main()
|
||
Point p; //определяем структуру в стеке
|
||
{
|
||
p.y = p.x = 0;
|
||
p.SetX(1);
|
||
}
|
||
|
||
При вызове процедуры являющейся методом класса ей неявным образом
|
||
передается адрес этого класса (структуры). В самой процедуре этот адрес
|
||
доступен через имя параметрической переменной <b>this</b>. Эту переменную
|
||
автоматически генерирует компилятор. Если в объявление процедуры в
|
||
структуре указать ключевое слово <b>static</b>, то такой процедуре адрес
|
||
класса не передается и переменная <b>this</b> не генерируется.
|
||
|
||
Процедура объявленная в структуре может быть динамической. Для этого,
|
||
при ее определении, в самом ее начале, надо написать символ двоеточия <b>:</b>
|
||
(также как и для обычных динамических процедур). Но такая динамическая
|
||
процедура не может быть использована как макрос.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.15.2>
|
||
11.15.2 Наследование.
|
||
</h2>
|
||
|
||
В C-- поддерживаются простые и множественные наследования. Объявление
|
||
структуры с наследованием имеет следующий синтаксис:
|
||
|
||
struct Derived : Base1, Base2, ... Basen
|
||
{
|
||
int x0;
|
||
};
|
||
|
||
Число базовых структур в производном не ограничено. При множественном
|
||
наследовании структура может наследовать два и более экземпляра базовой
|
||
структуры. При этом возникает неоднозначность. Пример:
|
||
|
||
struct A
|
||
{
|
||
int x,y;
|
||
. . .
|
||
};
|
||
|
||
struct B : A //структура <b>B</b> наследует <b>A</b>
|
||
{
|
||
. . .
|
||
|
||
};
|
||
|
||
struct C : A //структура <b>C</b> наследует <b>A</b>
|
||
{
|
||
. . .
|
||
};
|
||
|
||
struct D : B, C //структура <b>D</b> наследует <b>B и C</b>
|
||
{
|
||
. . .
|
||
};
|
||
|
||
void main()
|
||
D d; //выделяем для структуры <b>D</b> память в стеке и присваиваем ей имя <b>d</b>
|
||
{
|
||
d.x0=0;
|
||
|
||
В этом примере структура <b>D</b> наследует два экземпляра структуры <b>A</b> и
|
||
в ней находятся два элемента с именем <b>x0</b>. Компиляторы C++ при записи
|
||
типа <b>d.x0=0</b> выдают сообщение об ошибке. C-- эту запись обрабатывает,
|
||
присваивание производится по умолчанию в элемент из последней базовой
|
||
структуры, имеющей элемент <b>x0</b>. Для того чтобы получить доступ ко
|
||
второму элементу <b>x0</b> (физически этот элемент находится в структуре
|
||
первым), необходимо применить операцию разрешения видимости:
|
||
|
||
d.B::x0=0;
|
||
|
||
Из всего этого следует, что записи:
|
||
|
||
d.x0=0;
|
||
и
|
||
d.C::x0=0;
|
||
|
||
являются равнозначными.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=11.15.3>
|
||
11.15.3 Наследование процедур.
|
||
</h2>
|
||
|
||
Если в базовом классе есть процедура, а в производном классе Вы эту
|
||
процедуру переопределили, то эта процедура будет переопределена и в
|
||
базовом классе. Таким образом процедура определенная в базовом классе
|
||
будет потеряна. Пример:
|
||
|
||
struct Point // базовый класс
|
||
{
|
||
int x; // элементы данных
|
||
int y; // класса типа Point
|
||
void SetX(int); // объявление методов
|
||
void SetY(int); // класса Point
|
||
};
|
||
|
||
void Point::SetX(int _x) // определение процедуры класса Point
|
||
{
|
||
IF((_x>=0)&&(_x<=MAX_X)) x=_x;
|
||
}
|
||
|
||
struct Point2 : Point // производный класс
|
||
{
|
||
int x2;
|
||
}
|
||
|
||
struct Point3 : Point // еще один производный класс
|
||
{
|
||
int z;
|
||
}
|
||
|
||
void Point3::SetX(int _x) // в этом производном классе переопределяем
|
||
{ // процедуру SetX
|
||
IF((_x>=80)&&(_x<=MAX_X)) x=_x;
|
||
}
|
||
|
||
Процедура SetX, определенная в базовом классе Point, теперь будет
|
||
недоступна. Вместо кода определенного в этом классе, будет вызываться код
|
||
процедуры, определенный в наследуемом классе Point3. При вызове процедуры
|
||
SetX из другого производного класса Point2 будет также вызываться код
|
||
процедуры, определенный в производном классе Point3. Переопределяя
|
||
процедуру таким образом, Вы замените код этой процедуры в базовом классе и
|
||
во всех его наследуемых классах.
|
||
|
||
Если Вам необходимо, чтобы код новой процедуры был доступен
|
||
одновременно с кодом старой процедуры, то в производном классе Вам
|
||
необходимо сделать еще одно объявление этой процедуры. Пример:
|
||
|
||
struct Point // базовый класс
|
||
{
|
||
int x; // элементы данных
|
||
int y; // класса типа Point
|
||
void SetX(int); // объявление методов
|
||
void SetY(int); // класса Point
|
||
};
|
||
|
||
void Point::SetX(int _x) // определение процедуры класса Point
|
||
{
|
||
IF((_x>=0)&&(_x<=MAX_X)) x=_x;
|
||
}
|
||
|
||
struct Point2 : Point // производный класс
|
||
{
|
||
int x2;
|
||
}
|
||
|
||
struct Point3 : Point // еще один производный класс
|
||
{
|
||
int z;
|
||
void SetX(int); // в наследуемом классе делаем еще одно объявление
|
||
// процедуры SetX
|
||
}
|
||
|
||
void Point3::SetX(int _x) // в этом производном классе переопределяем
|
||
{ // процедуру SetX
|
||
IF((_x>=80)&&(_x<=MAX_X)) x=_x;
|
||
EDI=this;
|
||
EDI.Point.SetX(_x); // делаем вызов одноименной процедуры из
|
||
// базового класса
|
||
}
|
||
|
||
Теперь из производного класса Point3 Вам доступны две различные
|
||
процедуры с одним именем SetX. А из базового класса Point и из другого
|
||
производного класса Point2 будет по прежнему доступен только базовый
|
||
вариант процедуры SetX.
|
||
<a href="#contents11"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.1>
|
||
12. Типы выходных файлов.
|
||
|
||
12.1 Выходные файлы типа COM.
|
||
</h2>
|
||
|
||
Этот тип выходного файла получается автоматически по умолчанию.
|
||
|
||
Изначально C-- мог делать только файлы формата типа COM. В настоящее
|
||
время появилась возможность получать файла типа EXE с моделями памяти tiny
|
||
и small для 16-битного кода, а также 32-битные для DOS и Windows. Также
|
||
есть возможность получения выходного файла в формате OBJ, что позволяет
|
||
связывать программы на C-- с программами на других языках.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.2>
|
||
12.2 Выходные файлы типа EXE.
|
||
</h2>
|
||
|
||
Этот формат файла можно получить, если компилировать с ключом командной
|
||
строки <b>/exe</b> или <b>/e</b>.
|
||
|
||
Возможно также поддержка EXE-формата через выходной файл формата OBJ,
|
||
который можно затем обработать линковщиком, не входящим в пакет C--.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.3>
|
||
12.3 Выходной файл *.EXE с моделью памяти tiny.
|
||
</h2>
|
||
|
||
Фактически код файла *.exe модели <b>tiny</b> ничем не отличается от кода
|
||
*.com. В сущности, это тот же com-файл, к которому добавлен 32-байтный
|
||
заголовок exe-файла. Единственное отличие возникает, когда Вы компилируете
|
||
файл с директивой <b>?resize TRUE</b>. В com-файле, по этой директиве, в код
|
||
программы добавляется соответствующий код, изменяющий размер доступной
|
||
памяти. В exe-файле для этих целей будет скорректирован заголовок
|
||
exe-файла.
|
||
|
||
Чтобы получить exe-файл с моделью памяти <b>tiny</b>, надо запустить
|
||
компилятор с ключом в командной строке <b>/TEXE</b>.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.4>
|
||
12.4 Объектный выходной файл OBJ.
|
||
</h2>
|
||
|
||
В настоящее время C-- может только создавать OBJ-файлы, но не может их
|
||
компоновать.
|
||
|
||
Ранее C-- создавал obj-файлы, которые могли быть подключены к проектам
|
||
созданным на других языках, т.е. ведомые (slave) модули. Причем из C--
|
||
модулей для основного проекта были доступны только процедуры и эти
|
||
процедуры не должны были использовать глобальные переменные.
|
||
|
||
Теперь же C-- может создавать основной модуль (master), который может
|
||
быть слинкован в самостоятельный файл.
|
||
|
||
Для obj-файлов появилась возможность использовать внешние (extern)
|
||
процедуры, переменные или структуры. Для этого достаточно их объявить как
|
||
extern. Причем ключевое слово extern должно быть всегда первым. Пример
|
||
объявления внешних объектов:
|
||
|
||
extern void cdecl _printf(); // объявление внешней процедуры _printf имеющей
|
||
// тип cdecl и тип возврата void
|
||
extern int buts,cubs; // объявление двух внешних переменных типа int
|
||
extern struct IPXL ipxl; // объявление внешней структуры ipxl имеющей тег
|
||
// IPXL, причем тег этой структуры должен быть
|
||
// описан ранее.
|
||
|
||
Появление возможности объявлять внешние объекты позволяет подключать к
|
||
obj-модулю на C-- модули написанные на других языках или подключать к
|
||
программе на C-- процедуры из библиотек на других языках. При объявлении
|
||
внешних объектов очень важно правильно указать тип процедуры и ее имя. Если
|
||
Вы будете использовать внешние процедуры, написанные на C то чаще всего,
|
||
Вам нужно будет указывать модификатор <b>cdecl</b>, а к имени процедуры или
|
||
переменной добавлять префикс <b>_</b>.
|
||
|
||
Из основного (master) obj-файла написанного на C-- для других
|
||
obj-модулей доступны все процедуры, глобальные переменные и глобальные
|
||
структуры.
|
||
|
||
Чтобы получить ведомый obj-модуль при компиляции надо использовать ключ
|
||
<b>/sobj</b>.
|
||
|
||
C-- может создавать obj-файлы с моделью памяти tiny и small. По
|
||
умолчанию создаются модули с моделью tiny. Чтобы получить obj-файл с
|
||
моделью памяти small надо запустить компилятор с ключами <b>/obj и /exe</b>.
|
||
|
||
Для создания obj-файлов для 32-битного DOS в командной строке Вам
|
||
необходимо указать ключи <b>/d32 и /obj</b>. Использовать полученный obj-файл мне
|
||
удалось лишь с помощью wlink и расширителя zrdx.exe.
|
||
|
||
Создание obj-файлов под windows не предусмотрено.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.5.1>
|
||
12.5 COM файл symbiosis.
|
||
|
||
12.5.1 СИМБИОЗ - что это такое?
|
||
</h2>
|
||
|
||
Транслятор C-- имеет ключ, позволяющий добавлять компилируемую
|
||
программу к концу уже имеющегося COM файла. Это называют COM-файл
|
||
Symbiosis. Когда такая программа запускается, управление сначала получает
|
||
добавленный код C--, и только после выполнения его процедуры main()
|
||
управление получит первоначальный код COM-файла.
|
||
|
||
Если добавленный вами код завершается EXIT() или ABORT(), программа
|
||
прекратится, и первоначальный код COM-файла не будет выполнен. Это
|
||
позволяет программе, добавленной к COM файлу, определять, будет ли
|
||
управление передано на первоначальный код.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.5.2>
|
||
12.5.2 Как это делать.
|
||
</h2>
|
||
|
||
Чтобы сделать это, Вы должны использовать ключ <b>/SYM</b> в командной
|
||
строке компилятора, в которой указывается полное имя COM-файла, к
|
||
которому что-то добавляется. При этом оригинал COM-файла не меняется, а
|
||
новый файл содержит его в себе. Например, чтобы откомпилировать программу
|
||
HELLO.C-- к концу копии C:\command.сом используют следующую команду:
|
||
|
||
C-- /SYM C:\COMMAND.COM HELLO.C--
|
||
|
||
Будет создан выходной файл HELLO.COM .
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.5.3>
|
||
12.5.3 Использование.
|
||
</h2>
|
||
|
||
Вы можете, вероятно, придумать большое количество путей использования
|
||
этой функции, типа:
|
||
|
||
- Добавление защиты с использованием пароля к некоторым
|
||
специальным COM файлам.
|
||
- Уменьшение памяти, доступной COM файлу при запуске.
|
||
- Инициализация режима видео для COM файла.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.5.4>
|
||
12.5.4 Злоупотребления.
|
||
</h2>
|
||
|
||
Любой злоумышленник может придумать и вредные применения для этой
|
||
функции. Наиболее очевидное из них - создание троянских коней. Я хотел бы
|
||
указать, что это неконструктивное использование C--, и любое
|
||
разрушительное использование симбиозов COM-файлов запрещено.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.6>
|
||
12.6 SYS - драйверы устройств.
|
||
</h2>
|
||
|
||
Компилятор значительно облегчит Ваш труд при написании драйверов.
|
||
Компилятор сам создаст заголовок драйвера и процедуры <b>СТРАТЕГИЯ</b> и
|
||
<b>ПРЕРЫВАНИЕ</b>. Вам остается лишь написать код обработки команд.
|
||
|
||
Что бы откомпилировать файл драйвера устройства, надо добавить в
|
||
командную строку ключ <b>/SYS</b>. Кроме того, появились новые директивы
|
||
компилятору, которые действуют только с этим ключом. Вот они:
|
||
|
||
<b>?sysattribute значение</b> - эта директива передает компилятору
|
||
атрибут создаваемого драйвера. По умолчанию устанавливается значение
|
||
0x2000.
|
||
|
||
<b>?sysname <текстовая строка></b> - эта директива передает компилятору
|
||
имя будущего драйвера. По умолчанию присваивается имя "NO_NAME". Длина
|
||
имени не более 8 символов.
|
||
|
||
<b>?syscommand command_0,command_1, ... command_n;</b> - эта директива
|
||
является обязательной. По этой директиве компилятору передается список имен
|
||
процедур обработки команд драйвера. Имена разделены запятыми. Список должен
|
||
заканчиваться символом точка-с-запятой. Можно передать не более 25 команд.
|
||
Если какая-то команда не имеет кода поддержки, то в список надо записать
|
||
слово NONE.
|
||
|
||
По умолчанию компилятор для драйвера не создает стек. Драйвер может
|
||
пользоваться системным стеком. Но, говорят, что он имеет маленькую глубину.
|
||
Если Ваши процедуры активно используют стек, и Вы не надеетесь на системный,
|
||
то директивой ?stack <величина> можно заставить драйвер пользоваться своим
|
||
стеком.
|
||
|
||
Вашим процедурам обработки команд при передаче управления в регистрах
|
||
ES:BX будет передан адрес заголовка запроса. Регистр DS равен CS. При
|
||
возврате управления ваши процедуры должны сохранить регистр DS. В регистре
|
||
AX должен находиться код возврата. Остальные регистры могут быть
|
||
использованы произвольным образом.
|
||
|
||
Процедуру обработки команды инициализации желательно располагать
|
||
последней (чтобы иметь возможность отдать адресное пространство занимаемое
|
||
этой процедурой операционной системе). Перед этой процедурой, если Вы в
|
||
других процедурах обработки команд используете динамические процедуры,
|
||
обязательно должна быть директива <b>?setdinproc</b>. Глобальные переменные должны
|
||
быть обязательно проинициализированы.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.7>
|
||
12.7 Компиляция кода расширителей ROM-BIOS.
|
||
</h2>
|
||
|
||
Расширители ROM-BIOS (BIOS видеоконтроллеров, сетевых карт...) имеют
|
||
определенную структуру и требования. C-- теперь может облегчить Вам процесс
|
||
создания кода ROM-BIOS. Если запустить компилятор на компиляцию с ключом
|
||
командной строки <b>/ROM</b>, то компилятор создаст сигнатуру (заголовок)
|
||
ROM-BIOS, заполнит оставшееся свободное место до указанного размера ПЗУ
|
||
кодом заполнения, подсчитает и скорректирует контрольную сумму ПЗУ.
|
||
|
||
Для этого режима компиляции есть несколько специфических директив:
|
||
|
||
1. <b>?sizerom value</b> - эта директива сообщает компилятору размер ПЗУ в
|
||
байтах. Если эта директива не указана, то компилятор сам выберет
|
||
минимальный подходящий размер ПЗУ из ряда: 1024, 2048, 4096, 8192, 16384,
|
||
32762 или 65536. Свободное от кода и данных место будут заполнены до конца
|
||
размера ПЗУ байтом заполнения определяемого директивой <b>?aligner</b>. По
|
||
умолчанию он равен нулю, для РПЗУ типа 27ххх этот байт имеет смысл сделать
|
||
равным 0xFF. Последний байт ПЗУ будет скорректирован компилятором таким
|
||
образом, чтобы контрольная сумма равнялась нулю.
|
||
|
||
2. <b>?movedatarom TRUE/FALSE</b> - эта директива сообщает компилятору есть ли
|
||
необходимость копировать данные из ПЗУ в ОЗУ. По умолчанию она установлена
|
||
в <b>FALSE</b>. Если эту директиву определить <b>TRUE</b>, то компилятор вставит в
|
||
область инициализации код перемещающий данные из ПЗУ в ОЗУ. При этом
|
||
регистр DS будет установлен на сегмент ОЗУ. Стек также будет переустановлен
|
||
на этот сегмент. Таким образом, процедура main получит управление с
|
||
регистрами <b>AX = ES = DS = SS = сегменту ОЗУ с перенесенными в него данными</b>.
|
||
Если эту директиву установить в <b>FALSE</b>, регистр DS все равно будет
|
||
переустановлен на адрес сегмента ОЗУ, так как Ваш код будет использовать
|
||
этот сегмент для неинициализированных глобальных переменных.
|
||
Инициализированные переменные останутся в ПЗУ и все обращения к ним будут
|
||
производиться через регистр CS. Так же останется не тронутым (таким, каким
|
||
его установил главный BIOS) и стек.
|
||
|
||
3. <b>?dataseg value</b> - этой директивой компилятору сообщается сегментный
|
||
адрес ОЗУ, который может быть использован вашим кодом. По умолчанию он
|
||
равен 0x70. Этот адрес вы можете узнать в любой момент, считав его из вашего
|
||
кода по смещению 4. Например: DS = CSWORD[4];
|
||
|
||
Некоторые замечания:
|
||
|
||
1. Не забывайте, что в момент инициализации ROM-BIOS, DOS еще не
|
||
загружен, и соответственно все процедуры использующие вызовы DOS работать
|
||
не будут.
|
||
|
||
2. Нельзя завершать работу программы процедурами <b>ABORT()</b> или <b>EXIT()</b> и им
|
||
подобным. Работа расширителя ROM-BIOS должна завершаться только выходом из
|
||
процедуры main().
|
||
|
||
3. Если директива <b>?movedatarom</b> установлена в <b>FALSE</b>, то будьте внимательны
|
||
при работе с инициализированными переменными. Они в этом режиме доступны
|
||
только для чтения, и адресуются через регистр CS.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.1>
|
||
12.8 32-битные файлы.
|
||
|
||
12.8.1 32-битный код под DOS.
|
||
</h2>
|
||
|
||
Для того чтобы откомпилировать 32-битную программу под DOS надо
|
||
запустить компилятор с ключом командной строки <b>/d32</b>. Но работа 32-битной
|
||
программы под DOS-ом невозможна без расширителя DOS. Для C-- можно
|
||
использовать DOS4GW или zrdx.exe или любой другой расширитель DOS. Чтобы
|
||
компилятор знал, где искать <b>stub</b> файл и его имя, надо в файл c--.ini
|
||
прописать строку stub=path_name_to_stub_file. Пример:
|
||
|
||
stub=c:\c--\zrdx.exe
|
||
|
||
Если не добавлять в c--.ini эту строку, то компилятор сгенерирует
|
||
32-битный exe-файл, но без расширителя DOS. Если в командной строке
|
||
вместе с ключом <b>/d32</b> указать и ключ <b>/ns</b>, то строка с переменной stub из
|
||
файла c--.ini будет аннулирована, и вы получите файл без расширителя DOS.
|
||
|
||
Для 32-битного DOS-файла можно использовать директивы компилятора
|
||
?parsecommandline TRUE/FALSE или его расширенный вариант <b>?argc
|
||
TRUE/FALSE</b>. Реализована и поддержка директивы <b>?atexit TRUE/FALSE</b>.
|
||
|
||
Сейчас для 32-битных DOS-файлов используется LE-формат. Так как LE
|
||
формат является стандартным, то теперь можно использовать почти любой
|
||
stub, понимающий этот формат. Файлы LE формата можно сжимать программами
|
||
типа UPX.EXE и ей подобными.
|
||
|
||
Если Вы используете stub, который затем загружает DOS4GW.EXE, то
|
||
начало Вашей программы должно иметь специальную сигнатуру. Компилятор
|
||
автоматически сформирует ее, если Вы в командной строке или в c--.ini
|
||
файле укажете ключ <b>/DOS4GW</b>. Такой ключ Вам необходимо будет применять,
|
||
если Вы будете использовать в качестве stub 4gs.exe.
|
||
|
||
Существует также поддержка блока кода использующего для перехода и
|
||
работы в 32-битном режиме возможности DPMI сервиса. Исходный текст этого
|
||
блока находится в файле startup.h-- и компилируется, если в командной
|
||
строке указана опция <b>/stub=dpmi</b> или в файле c--.ini написать строку
|
||
<b>stub=dpmi</b>. Недостатком этого способа перехода и работы в 32-битном
|
||
режиме являются необходимость обязательного функционирования на
|
||
запускаемом компьютере DPMI сервиса. Так как, программа загружается как
|
||
обычная DOS программа, и лишь в процессе работы переходит в 32-битный
|
||
режим работы, размер программы ограничен размером свободной DOS памяти.
|
||
Ну а преимуществом его является компактный размер исполняемого файла.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.2>
|
||
12.8.2 32-битный код под Windows.
|
||
</h2>
|
||
|
||
Для того чтобы откомпилировать программу, написанную под Windows надо
|
||
запустить компилятор с ключом командной строки <b>/w32</b>.
|
||
|
||
Если Вы в своей программе используете вызовы API-процедур, то эти
|
||
процедуры надо предварительно обязательно объявить. Объявление процедур
|
||
имеет следующую форму:
|
||
|
||
extern WINAPI "DLL_name"
|
||
{
|
||
returncode procname1();
|
||
returncode procname2();
|
||
procname3();
|
||
}
|
||
|
||
где:
|
||
DLL_name - имя и расширение dll-библиотеки, в которой находятся эти
|
||
процедуры.
|
||
returncode - тип возврата из api-процедур. По умолчанию он равен dword.
|
||
|
||
Программы, написанные под Windows, имеют одну немаловажную
|
||
особенность - все параметры в стековые процедуры передаются в обратном
|
||
порядке (так называемый C-стиль), но очистка стека от параметров
|
||
происходит в самих процедурах. Получается своеобразный гибрид <b>C и pascal</b>
|
||
стилей - <b>stdcall</b>.
|
||
|
||
С помощю ключа <b>/W32C</b> компилятор создает консольный файл под Windows.
|
||
|
||
Если при компиляции указывали опцию командной строки <b>/j0</b> или
|
||
директиву <b>#jumptomain NONE</b>, то Ваша программа будет компилироваться без
|
||
использования кода начальной инициализации, описание которого находится в
|
||
файле startup.h--.
|
||
|
||
Код начальной инициализации для программ под Windows имеет следующий
|
||
вид:
|
||
|
||
hThisInst=GetModuleHandleA(0);
|
||
#ifdef __CONSOLE__
|
||
hStdOut=GetStdHandle(-11);
|
||
#endif
|
||
lpszArgs=GetCommandLineA();
|
||
#ifdef __environ;
|
||
environ=GetEnvironmentStringsA();
|
||
#endif
|
||
main();
|
||
ExitProcess(EAX);
|
||
|
||
Таким образом, в глобальных переменных <b>hThisInst</b> будет находится
|
||
handl запущенного файла, а в <b>lpszArgs</b> адрес командной строки Вашего
|
||
файла. Если Вы в командной строке указали опции <b>/p</b> или <b>/argc</b> или в
|
||
начале вашего файла есть директивы <b>#parsecommandline TRUE</b> или <b>argc TRUE</b>,
|
||
то компилятор создаст дополнительный код сделающий разборку этой
|
||
командной строки на части. Если Вы компилируете консольную программу, то
|
||
в вашей программе будет еще одна глобальная переменная - <b>hStdOut</b>. В этой
|
||
переменной хранится handl стандартного вывода (экрана). Если Вы при
|
||
компиляции программы указали опцию <b>/env</b>, то в глобальной переменной
|
||
<b>environ</b> хранится адрес переменной окружения программы.
|
||
|
||
После завершения работы процедуры <b>main</b> выполнятся процедура
|
||
<b>ExitProcess</b>, которой в качестве параметра передается регистр EAX. Т.о.
|
||
Вам для завершения работы программы будет достаточно сделать выход из
|
||
процедуры <b>main</b>, предварительно загрузив в регистр EAX нужный Вам код
|
||
возврата.
|
||
|
||
Некоторые компиляторы создают DLL, в которых имена экспортируемых
|
||
процедур имеют такой формат:
|
||
|
||
ProcName@8
|
||
|
||
В этом имени после символа <b>@</b> указывается размер стека с
|
||
параметрами, передаваемых процедуре.
|
||
|
||
Объявлять такие процедуры нужно так:
|
||
|
||
extern WINAPI "name.dll"
|
||
{
|
||
ProcName@8 ;
|
||
}
|
||
|
||
т.е. без круглых скобок. В программе, при обращении к такой процедуре, ее
|
||
имя надо писать без суффикса @8, т.е. вот так - ProcName(param1,param2);
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.3>
|
||
12.8.3 Вызов API процедур по ординалам.
|
||
</h2>
|
||
|
||
В динамически подключаемых библиотеках (DLL) каждой процедуре, кроме
|
||
ее имени, соответствует уникальное число, которое называется ординалом. И
|
||
поэтому, кроме общепринятого вызова API-процедуры по имени, можно делать
|
||
вызов и по ординалу. Теоретически, при использовании вызова по ординалу,
|
||
загрузка файла должна происходить быстрее. Так как в выходной файл не
|
||
будут включены списки имен процедур, вызов которых производится по
|
||
ординалам, то выходной файл может получиться немного меньшим по размеру.
|
||
|
||
Чтобы компилятор создал файл, использующий вызов API-процедур по
|
||
ординалам, надо сделать две вещи:
|
||
|
||
1. Разрешить компилятору это делать. Для этого надо в опциях командной
|
||
строки (или в файле C--.INI) указать ключ <b>WO</b>.
|
||
|
||
2. Сообщить компилятору - какой номер ординала соответствует какому
|
||
имени процедуры. Процедуры, для которых не был указан ординал, будет
|
||
создан вызов по имени. Установить соответствие имен процедур ординалу
|
||
можно двумя способами:
|
||
|
||
a). Автоматически, с помощью опции командной строки <b>IND=name.dll</b>,
|
||
по которой компилятор просканирует эту библиотеку и импортирует из
|
||
нее все имена и ординалы процедур. (Импорт возможет только из
|
||
библиотек имеющих формат PE).
|
||
|
||
b). В ручную указать в объявлении API-процедур и ее ординал. Делается
|
||
это так: после имени процедуры ставится точка, а за ней указывается
|
||
номер ординала. Вот пример объявления API-процедуры с указанием ее
|
||
ординала:
|
||
|
||
extern WINAPI "user32.dll"
|
||
{
|
||
............
|
||
long MessageBoxA.429();
|
||
............
|
||
}
|
||
|
||
В библиотеках (DLL), иногда существуют процедуры, для которых не
|
||
указано их имя, но указан номер ординала. Вызов таких процедур по имени
|
||
не возможен, но можно это сделать по ординалу (если, конечно Вы знаете,
|
||
для чего эта процедура и что она делает). Для этого в объявлении
|
||
API-процедуры Вам надо придумать для этой процедуры уникальное имя и
|
||
указать реальный ординал. Затем в программе Вы будете обращаться к этой
|
||
процедуре по вымышленному имени. Но если Вы случайно откомпилируете такой
|
||
файл без ключа <b>WO</b>, то при запуске этой программы Вы получите сообщение,
|
||
о том, что данного имени в библиотеке нет.
|
||
|
||
К сожалению, нет никаких гарантий того, что номер ординала для данной
|
||
процедуры не изменится при смене версии динамической библиотеки. Поэтому
|
||
использовать ординалы надо осторожно.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.4>
|
||
12.8.4 Создание DLL под Windows.
|
||
</h2>
|
||
|
||
Динамически подключаемые библиотеки позволят получать более
|
||
компактные программы и ускорить процесс компиляции. К минусам
|
||
использования DLL можно отнести необходимость наличия самих файлов DLL на
|
||
запускаемом компьютере и немного увеличивается время запуска программы.
|
||
|
||
Для того чтобы процедура стала доступной для других программ надо в
|
||
исходном тексте перед именем процедуры прописать ключевое слово - <b>_export</b>.
|
||
Пример:
|
||
|
||
void _export testproc()
|
||
{
|
||
....
|
||
}
|
||
|
||
Для того чтобы создать DLL, нужно написать файл, в котором будут
|
||
процедуры с ключевыми словами <b>_export</b>. Вспомогательные процедуры, которые
|
||
могут понадобиться для работы основных экспортируемых процедур, объявлять
|
||
как <b>_export</b> необязательно. Затем этот файл нужно откомпилировать с ключом
|
||
/dll. В результате Вы получите готовую динамически подключаемую
|
||
библиотеку.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.5>
|
||
12.8.5 Инициализация DLL при загрузке.
|
||
</h2>
|
||
|
||
Иногда, для работы процедур из динамических библиотек (DLL), бывает
|
||
необходимым инициализировать некоторые переменные значениями, зависящими
|
||
от текущего состояния операционной системы, например, получить дескриптор
|
||
этой библиотеки.
|
||
|
||
Директивой <b>#jumptomain NONE (-j0)</b> управление при запуске передается
|
||
сразу на процедуру main.
|
||
|
||
Во всех остальных случаях генерируется код заглушки и управление на
|
||
процедуру main не передается. Фактически процедура main в этом случае не
|
||
нужна.
|
||
|
||
Процедура main при создании файлов DLL должна выглядеть немного иначе,
|
||
чем в других случаях:
|
||
|
||
dword main ( dword hInstDLL, reason, reserv )
|
||
{
|
||
...
|
||
}
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.8.6>
|
||
12.8.6 Компиляция ресурсов.
|
||
</h2>
|
||
|
||
Встроенный в C-- компилятор ресурсов по своим возможностям уступает
|
||
специализированным компиляторам ресурсов, но этих возможностей, как мне
|
||
кажется, будет достаточно для большинства Ваших задач.
|
||
|
||
Будет проще перечислить то, что встроенный в C-- компилятор ресурсов
|
||
не умеет делать. Не обрабатываются операторы ресурсов: <b>VERSION</b>,
|
||
<b>VERSIONINFO</b> и определяемые пользователем ресурсы. При необходимости,
|
||
данные, вводимые с помощью этих операторов, можно ввести с помощью
|
||
оператора <b>RCDATA</b>. У многих операторов ресурсов есть необязательные
|
||
параметры <b>loading</b> и 'memory'. Поддержка этих параметров не
|
||
реализована. Встретив эти параметры, компилятор их просто пропустит.
|
||
|
||
Заставить компилятор C-- обрабатывать ресурсы можно двумя способами:
|
||
|
||
1. Включить в свой проект директивой <b>#include</b> файл с расширением
|
||
<b>.rc</b>. Файлы с таким расширением компилятор считает файлом с ресурсами.
|
||
Файл ресурсов необходимо включать в Ваш проект лишь после включения
|
||
заголовочных файлов Windows.
|
||
|
||
2. Ресурсы можно располагать в теле исходного текста программы в
|
||
произвольном месте. Текст ресурсов должен начинаться с директивы <b>#pragma
|
||
resource start</b>, а заканчиваться директивой <b>#pragma resoutce end</b>.
|
||
Ресурсы могут быть разделенными на части и эти части можно располагать в
|
||
любом удобном для Вас месте (глупо располагать ресурсы в блоке
|
||
комментариев и потом удивляться, почему они не были откомпилированы).
|
||
Компилятор соберет эти части и откомпилирует.
|
||
|
||
Имена операторов можно писать как большими, так и маленькими буквами,
|
||
но имена идентификаторов чувствительны к регистру. В тексте ресурсов
|
||
можно использовать директивы и комментарии.
|
||
|
||
Ничто не мешает Вам использовать компиляторы ресурсов от других
|
||
языков. Главное, чтобы синтаксис файла ресурсов соответствовал выбранному
|
||
компилятору.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=12.9>
|
||
12.9 Выходные файлы для MeOS.
|
||
</h2>
|
||
|
||
Исполняемые файлы для операционной системы MenuetOS поддерживаются
|
||
компилятором совсем недавно. Для того, чтобы откомпилировать файл для
|
||
<b>MenuetOS</b>, нужно в опциях компилятору указать <b>/meos</b>. Вы получите файл без
|
||
расширения, который потом можно будет выполнить в среде операционной
|
||
системы MenuetOS.
|
||
|
||
Если при компиляции файла Вы не указывали опцию <b>/j0</b> или не
|
||
использовали директиву <b>#jumptomain NONE</b>, то компилятор будет использовать
|
||
файл начальной инициализации <b>startup.h--</b>, в котором для операционной
|
||
системы MenuetOS создан блок инициализации и завершения программы.
|
||
Завершать выполнение таких программ можно просто выйдя из процедуры <b>main</b>.
|
||
<a href="#contents12"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.1>
|
||
13. Приложения.
|
||
|
||
13.1 Поиск включаемых файлов.
|
||
</h2>
|
||
|
||
Поиск включаемого в вашу программу файла, имя которого объявляется
|
||
директивой <b>include</b> и заключено в двойные кавычки "", производится
|
||
компилятором по такой схеме:
|
||
|
||
сначала делается попытка открыть файл в текущей директории. Если файла там
|
||
нет, то далее делается попытка открыть файл в директории указанной
|
||
директивой <b>#includepath</b>. Если директива не была задана или файла в этой
|
||
директории не оказалось, то делается попытка открыть файл в директории
|
||
указанной в командной строке командой <b>/ip=path</b>. Если эта команда не была
|
||
задана или файла в указанной директории не оказалось, то делается попытка
|
||
открыть файл в директории указанной в файле C--.INI командой <b>ip=</b>. Если эта
|
||
команда не была задана или файла в указанной директории не оказалось, то
|
||
делается попытка открыть файл в директории, на которую указывает переменная
|
||
окружения C--. Если переменная окружения не была задана или файла в этой
|
||
директории не оказалось, то делается последняя попытка открыть файл в
|
||
директории, откуда был запущен компилятор.
|
||
|
||
Если имя включаемого файла заключено в угловые скобки < >, то поиск
|
||
этого файла производится в противоположном направлении, за исключением
|
||
того, что поиск в текущей директории не производится.
|
||
|
||
Для консольной версии компилятора имена главного модуля и включаемых
|
||
файлов могут иметь длину более 8 символов.
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.2>
|
||
13.2 Регистры, которые должны быть сохранены.
|
||
</h2>
|
||
|
||
Регистры, которые должны сохраняться - BP, DI, SI, DS, SS, SP, CS и IP.
|
||
|
||
BP используется как указатель на локальные и параметрические
|
||
переменные в стеке, что и требует его сохранения.
|
||
|
||
DI и SI сохранять не обязательно, если программист осознает
|
||
последствия. DI и SI часто используются для индексации массивов, как
|
||
например в формуле:
|
||
|
||
dog = firehydrant(1,red) + legs[DI];
|
||
|
||
Если DI не сохранялся в процедуре firehydrant, значение, присвоенное
|
||
переменной dog, скорее всего, будет неправильным, поскольку индекс для
|
||
массива legs был изменен. В сущности, для точного согласования все
|
||
процедуры должны иметь специальное указание в комментарии на то, что в них
|
||
не сохраняется содержимое регистров DI и/или SI.
|
||
|
||
DS указывает на сегмент данных, и все операции с глобальными
|
||
переменными пользуются этим значением.
|
||
|
||
SS хранит сегмент стека и должен сохраняться. SP указывает на текущую
|
||
позицию в стеке и тоже должен сохраняться.
|
||
|
||
CS хранит сегмент кода программы. Все команды выбираются с
|
||
использованием CS и IP, следовательно их значения должны сохраняться. IP,
|
||
как известно, указатель адреса команды, и CS и IP непосредственно не могут
|
||
изменяться в процессорах 8086, 8088, 80286, 80386, 80486,...
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.3>
|
||
13.3 C--.ini файл.
|
||
</h2>
|
||
|
||
C--.ini файл предназначен для предустановки по умолчанию параметров
|
||
компилятора.
|
||
|
||
Сейчас компилятор поддерживает огромное число параметров командной
|
||
строки. Правильное их использование позволит Вам получать более компактный
|
||
код и может значительно облегчить Вам отладку программы. Но так как этих
|
||
параметров очень много набирать их каждый раз в командной строке бывает
|
||
утомительно и не исключена возможность пропустить какой-нибудь параметр.
|
||
Чтобы избавить Вас от всех этих напастей и был введен c--.ini файл.
|
||
|
||
Параметры командной строки прописываются в этом файле построчно.
|
||
Синтаксис тот же, что и в командной строке, но без ведущего обратного слэша
|
||
или минуса. Если файл расположен в директории, на которую указывает
|
||
переменная окружения <b>set c--=<path></b> или если эта переменная не определена,
|
||
то в той же директории где и файл c--.exe, то эти параметры
|
||
распространяются на все компилируемые программы. Если же файл c--.ini
|
||
расположен в текущей директории, то параметры считываются только из этого
|
||
файла и действуют только для текущего проекта.
|
||
|
||
Допустимо использование комментариев. Признаком начала комментария
|
||
является символ <b>;</b>. Все последующие символы после <b>;</b> и до конца строки
|
||
считаются комментарием.
|
||
|
||
Пример C--.ini файла:
|
||
|
||
r-
|
||
X
|
||
3 ;это комментарий
|
||
os
|
||
|
||
ini-файл может иметь любое имя (но расширение должно быть обязательно
|
||
ini). Имя этого файла с расширением должно быть передано компилятору в
|
||
командной строке. Файл c--.ini загружается и обрабатывается автоматически
|
||
до загрузки файла указанного в командной строке.
|
||
|
||
Таким образом, файл *.ini можно использовать подобно make-файлу - в нем
|
||
Вы можете указать и имя главного компилируемого модуля, и все необходимые
|
||
для его компиляции настройки.
|
||
|
||
Как альтернативу c--.ini файлу, параметры командной строки можно
|
||
прописывать непосредственно в начале главного файла компилируемого проекта,
|
||
используя директиву <b>pragma option</b>. С одной стороны это обеспечит Вашему
|
||
проекту независимость от настроек компилятора, если Ваш проект будет
|
||
компилироваться на другом компьютере. Но с другой стороны некоторые
|
||
настройки являются индивидуальными для данного компьютера (это расположение
|
||
библиотек, имена и расположение stub-файлов). Какой вариант использовать
|
||
решать Вам, но как говорят, и я с этим согласен, лучше пользоваться золотой
|
||
серединой - Часть параметров прописать в c--.ini файле, а другую
|
||
непосредственно в компилируемом файле.
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.4>
|
||
13.4 startup.h-- файл.
|
||
</h2>
|
||
|
||
В этом файле находятся исходные тексты, которые компилируются
|
||
компилятором в код начальной инициализации файла, для всех поддерживаемых
|
||
компилятором типов выходных файлов. Этот файл должен находится либо в
|
||
директории вместе с компилятором, либо в директории с библиотечными файлами.
|
||
Этот файл включается компилятором в проект автоматически, а включение его
|
||
директивой <b>include</b> может привести к нежелательным результатам.
|
||
|
||
В блоке начальной инициализации программы может производится (если Вы
|
||
это укажете с помощью опций командной строки или используя директивы),
|
||
разбор командной строки на параметры, сохранение переменой окружения,
|
||
поддержка работы процедуры <b>ATEXIT</b>, изменение размера доступной памяти для
|
||
*.com файлов и многие другие подготовительные операции. Если Вы
|
||
откомпилируете свой файл не используя никаких опций командной строки и у
|
||
Вас будет отсутствовать c--.ini файл, а в самом компилируемом файле у Вас
|
||
будут отсутствовать директивы, то при компиляции *.com файла в него будет
|
||
включен блок изменяющий размер доступной памяти и сигнатура <b>SPHINXC--</b>.
|
||
|
||
Если Вы компилируете файл типа *.exe (кроме файла модели tiny для DOS)
|
||
и используете директиву <b>jumptomain NONE</b> или ключ командной строки <b>/j0</b>,
|
||
то для этого проекта файл startup.h-- компилятором не используется. Не
|
||
используется этот файл также при компиляции *.com файлов если, кроме <b>/j0</b>,
|
||
в этом проекте не используется разбор командной строки (<b>/p /argc</b>), не
|
||
применяется процедура <b>ATEXIT (/at)</b>, не используется адрес переменной
|
||
окружения <b>(/env)</b>, не используется очистка области post-адресов <b>(/cpa)</b>, не
|
||
используется уменьшение доступной программе памяти <b>(/r)</b> и не используется
|
||
заглушка нажатий <b>CTRL-C (/c)</b>.
|
||
|
||
Кроме блока начальной инициализации программы в файле startup.h--
|
||
находятся динамические процедуры:
|
||
|
||
void CLEARPOSTAREA( (E)AX ); - очистка post-области данных.
|
||
unsigned int PARAMSTR( ECX ); - получить адрес элемента командной строки
|
||
unsigned int PARAMCOUNT(); - получить число элементов в командной строке
|
||
|
||
При разборе командной строки на составляющие ее элементы для 32-битных
|
||
программ реализована поддержка длинных имен. Для 16-битных программ
|
||
поддержка разбора командной строки с учетом длинных имен подключается, если
|
||
Вы в начале свой программы укажете директиву:
|
||
|
||
#define _USELONGNAME TRUE
|
||
|
||
либо в c--.ini файле или в командной строке компилятора укажете опцию
|
||
<b>d=_USELONGNAME</b>.
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.5>
|
||
13.5 mainlib.ldp файл.
|
||
</h2>
|
||
|
||
В этом файле находится большое число процедур из основной библиотеки
|
||
компилятора в уже откомпилированном виде. Все процедуры откомпилированы в
|
||
4-х различных режимах оптимизации. В этот файл также вынесены многие
|
||
процедуры, которые ранее были внутри компилятора. Использование ранее
|
||
откомпилированных процедур повышает скорость компиляции.
|
||
|
||
Эти процедуры откомпилированы только для 16-битного режима работы
|
||
программы. Если Вы будете использовать эти процедуры в 32-битной программе,
|
||
то компилятор на это не выдаст никаких сообщений и включит эту процедуру в
|
||
Ваш код. Но при запуске такой программы она неизбежно потерпит крах.
|
||
|
||
Использовать эту библиотеку очень просто. Все что нужно, это
|
||
расположить эту библиотеку в одной с компилятором директории. Тогда
|
||
компилятор, если встретит в вашей программе вызов процедуры, которая не
|
||
была определена ни во включаемых в программу библиотечных файлах, ни в
|
||
вашей программе, будет искать эту процедуру в файле mainlib.ldp. Если эта
|
||
процедура будет найдена в этом файле, то ее код будет перенесен в Ваш файл,
|
||
иначе будет выдано сообщение о неизвестной процедуре. Таким образом, чтобы
|
||
процедура была вставлена в вашу программу из библиотеки mainlib.ldp Вам
|
||
нужно в свою программу не включать библиотечный файл, содержащий процедуру с
|
||
таким же именем.
|
||
|
||
Список процедур находящихся в этой библиотеке можно получить с помощью
|
||
специальной программы cmmlib.exe. Эту программу можно найти в архиве
|
||
cmmlib.rar. Извлеките программу cmmlib.exe из этого архива и расположите ее
|
||
в одной с компилятором директории. Затем запустите эту программу с ключом
|
||
/L и Вы получите список процедур находящихся в этой библиотеке.
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
|
||
<h2 id=13.6>
|
||
13.6 C-- символы.
|
||
</h2>
|
||
|
||
SYMBOL|FUNCTION |EXAMPLE
|
||
--------------------------------------------------------------------
|
||
/* |начинают блок комментария |/* комментарий */
|
||
*/ |завершают блок комментария|/* комментарий */
|
||
| |
|
||
// |комментарий до конца линии|// комментарий
|
||
| |
|
||
= |присвоение |AX = 12;
|
||
+ |сложение |AX = BX + 12;
|
||
- |вычитание |house = dog - church;
|
||
* |умножение или указатель |x = y * z; AL = * var;
|
||
/ |деление |x1 = dog / legs;
|
||
& |поразрядное логическое И |polution = stupid & pointless;
|
||
| |поразрядное логическое ИЛИ|yes = i | mabe;
|
||
^ |поразрядн. исключающее ИЛИ|snap = got ^ power;
|
||
<< |битовый сдвиг влево |x = y << z;
|
||
>> |битовый сдвиг вправо |x = y >> z;
|
||
| |
|
||
+= |сложение |fox += 12; // fox = fox +12;
|
||
-= |вычитание |cow -= BX; // cow = cow - BX;
|
||
*= |умножение |a *= b; // a = a * b;
|
||
/= |деление |a /= b; // a = a / b;
|
||
&= |поразрядное логическое И |p &= q; // p = p & q;
|
||
|= |поразрядное логическое ИЛИ|p |= z; // p = p | z;
|
||
^= |поразрядн. исключающее ИЛИ|u ^= s; // u = u ^ s;
|
||
<<= |битовый сдвиг влево |x <<= z; // x = x << z
|
||
>>= |битовый сдвиг вправо |x >>= z; // x = x >> z
|
||
| |
|
||
>< |обмен значениями |x >< y; /* меняет местами значения x и y */
|
||
| |
|
||
== |проверка на равенство |IF(AX == 12)
|
||
> |проверка на больше чем |IF(junk > BOGUS)
|
||
< |проверка на меньше чем |if( x < y )
|
||
>= |проверка больше или равно |if(AX >= 12)
|
||
<= |проверка меньше или равно |IF(BL >= CH)
|
||
!= |проверка на неравенство |IF(girl != boy)
|
||
<> |проверка на отличие |if (cat<>dog) /* та же функция что != */
|
||
| |
|
||
@ |вставка кода |@ COLDBOOT(); /* вставляет COLDBOOT код */
|
||
: |динамическая процедура |: functionname () //объявляет functionname
|
||
$ |ассемблерная команда |$ PUSH AX /* заносит AX в стек */
|
||
# |получение адреса(смещения)|loc = #cow; /* loc = address of cow */
|
||
|или директива | #resize FALSE
|
||
! |оператор NOT или смена |!x_var; if(!proc())
|
||
|флага операции сравнения. |
|
||
... |любое число параметров в | void proc(...);
|
||
:: |разрешение видимости | ::var=0;
|
||
<a href="#contents13"><FONT size=-1 COLOR="#ff0000">Return to contents.</FONT></A>
|
||
|
||
</PRE>
|
||
</body>
|
||
<br><br>
|
||
</HTML>
|