Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Сабуров С.В. - Язык программирования C и C++ - 2006

.pdf
Скачиваний:
312
Добавлен:
13.08.2013
Размер:
1.42 Mб
Скачать

Справочник по работе с DOS

Единственное предположение, которое делает компоновщик, состоит в том, что программа управления оверлеями воспринимает вектор прерываний (обычно INT 3FH), через который происходит управление динамической загрузкой. Такой уровень «прозрачности» упрощает создание пользовательских программ управления оверлеями, наилучшим образом управляющих требованиям конкретной прикладной программы.

Оверлеи и обработка исключительных ситуаций

Если вы пишете оверлейную программу, содержащую конструкции для обработки исключительных ситуаций, то существует ряд ситуаций, которых следует избегать. Следующие программные элементы не могут содержать конструкцию обработки исключительных ситуаций:

Не расширяемые подставляемые функции.

Шаблоны функций.

Функции элементы или шаблоны классов.

Конструкция обработки исключительной ситуации включает в себя написанный пользователем блок try/catch и __try/__except. Кроме того, компилятор также может включать обработчики исключительных ситуаций и блоки с локальными динамическими переменными, спецификациями исключительных ситуаций и некоторые выражения new/delete.

Если вы пытаетесь использовать в оверлее вышеуказанные конструкции обработки исключительных ситуаций, компоновщик идентифицирует функцию и модуль следующим сообщением:

Error: Illegal local public in функция in module модуль

Когда эта ошибка вызывается подставляемой функцией, вы можете переписать функцию таким образом, чтобы она не была подставляемой. Если это вызвано шаблоном функции, можно сделать следующее:

удалить из функции все конструкции обработки исключительной ситуации;

удалить функцию их оверлейного модуля.

Особенно внимательно нужно строить оверлейную программу, которая использует множественное наследование. Попытка создать оверлейный модуль, который определяет или

197

Справочник по работе с DOS

использует конструкторы или деструкторы классов с множественным наследованием может привести к тому, что компоновщик будет генерировать следующее сообщение об ошибке:

Error: Illegal local public in класс: in module модуль

Когда генерируется такое сообщение, идентифицированный компоновщиком модуль не следует делать оверлейным.

В классе контейнера (в BIDS?.LIB) есть механизм обработки исключительной ситуации, который по умолчанию выключен. Однако диагностическая версия генерирует исключительные ситуации и не может использоваться в оверлеях. По умолчанию класс string может генерировать исключительные ситуации, и его не следует использовать в программах с оверлеями.

Использование оверлеев

Для создания программы с оверлейной структурой все ее модули должны компилироваться с включенным параметром компилятора Y. Для того, чтобы сделать оверлейным конкретный модуль, его следует компилировать с параметромYo. ( Yo автоматически включает параметр Y).

Параметр Yo распространяется на все модули и библиотеки, следующие за ней в командной строке компилятора BCC. Отменить ее можно, задав Yo . Эти два параметра являются единственными параметрами командной строки, которые могут следовать после имен файлов. Например, для того, чтобы сделать оверлейным модуль OVL.C, но не библиотеку GRAPHICS.LIB, можно использовать любую из следующих командных строк:

BCC ml Yo ovl.c Yo graphics.lib

или

BCC ml graphics.lib Yo ovl.c

Если при запуске компоновщика TLINK явно задана компоновка файла .EXE, то в командной строке компоновщика должен задаваться параметр /o.

Предположим, вы хотите иметь оверлейную структуру в программе, состоящей из трех модулей: MAIN.C, O1.C и O2.C. Оверлеями должны являться модули O1.C и O2.C. (Программа MAIN.C содержит зависящие от текущего времени подпрограммы и обработчики прерываний и потому должна оставаться резидентной). Предположим, что данная программа использует

198

Справочник по работе с DOS

модель памяти large.

Следующая команда позволяет выполнить данную задачу:

BCC ml Y main.c Yo o1.c o2.c

В результате получится выполняемый файл MAIN.EXE с двумя оверлеями.

Разработка программ с оверлеями

Этот раздел содержит важные сведения о разработке программ с оверлеями с хорошими характеристиками.

При компиляции оверлейного модуля вы должны использовать большую модель памяти (medium, large или huge). При всяком вызове функции из оверлейного модуля вы обязаны гарантировать, что все активные в текущий момент функции являются дальними.

Вы обязаны компилировать все оверлейные модули с параметром Y, что обеспечит оверлейную структуру генерируемого кода.

Невыполнение требования дальних вызовов в оверлейной программе приведет при выполнении программы к непредсказуемым и возможно, катастрофическим результатам.

Размер оверлейного буфера по умолчанию в два раза превышает размер самого большого оверлея. Для большинства прикладных программ такое умолчание вполне адекватно. Однако, представим себе ситуацию, когда какая либо функция программы реализована несколькими модулями, каждый из которых является оверлейным. Если общий размер этих модулей превышает размер оверлейного буфера, то если модули часто вызывают друг друга, это приведет к интенсивному свопингу.

Очевидно, что решение здесь заключается в увеличении размера оверлейного буфера до таких размеров, чтобы в любой момент времени в нем помещались все часто вызывающие друг друга оверлеи. Это можно сделать, установив через глобальную переменную _ovrbuffer требуемый размер в параграфах. Например, для установки размера оверлейного буфера равным 128К, включите в ваш код следующий оператор:

unsigned _ovrbuffer = 0x2000;

Общей формулы для определения идеального размера

199

Справочник по работе с DOS

оверлейного буфера не существует.

Не создавайте оверлейных модулей, содержащих обработчики прерываний, а также в случаях небольших или критичных к быстродействию программ. Вследствие нереентерабельной природы операционной системы DOS модули, которые могут вызываться функциями прерываний, не должны быть оверлейными.

Программа управления оверлеями Borland C++ полностью поддерживает передачу оверлейных функций как аргументов, присвоение и инициализацию переменных типа указателя функции, адресующих оверлейные функции, а также вызов оверлейных подпрограмм через указатели функций.

Отладка оверлейных программ

Большинство отладчиков либо имеет весьма ограниченные средства отладки программ с оверлейной структурой, либо вообще не имеет таких средств. Иначе дело обстоит с интегрированным со средой разработки программ отладчиком Borland C++ и автономным отладчиком фирмы Borland (Turbo Debugger). Оба эти отладчика полностью поддерживают пошаговую отладку и установку точек останова в оверлеях совершенно «прозрачным» для вас способом. Благодаря использованию оверлеев вы имеете возможность легко разрабатывать и отлаживать громоздкие прикладные программы — как в интегрированной среде, так и при помощи Turbo Debugger.

Внешние подпрограммы в оверлеях

Подобно обычным функциям языка Си, внешние (external) подпрограммы на языке Ассемблера, чтобы хорошо работать с подсистемой управления оверлеями, должны подчиняться некоторым правилам.

Если подпрограмма на языке ассемблера выполняет вызов любой оверлейной функции, то такая подпрограмма должна иметь объявление FAR и устанавливать границу стека при помощи регистра BP. Например, если OtherFunc — это оверлейная функция в другом модуле, и ее вызывает подпрограмма на языке Ассемблера ExternFunc, то тогда

ExternFunc должна быть дальней (FAR) и устанавливать границы

200

Справочник по работе с DOS

стека, как показано ниже:

 

 

 

ExternFunc

PROC

FAR

 

 

push

bp

;

сохранить

bp

mov

bp,sp

;

установить

стек

sub

sp,LocalSize

;

распределить

 

 

;

локальные

 

 

 

;

переменные

 

...

 

 

 

 

call

OtherFunc

;

вызов другого

 

 

;

оверлейного

 

 

;

модуля

 

...

 

 

 

 

mov

sp,bp

;

освобождение

 

 

;

локальных

 

 

 

;

переменных

 

pop

bp

;

восстановление BP

RET

 

;

возврат

 

ExternFunc

ENDP

 

 

 

где LocalSize — это размер локальных переменных. Если LocalSize равен нулю, вы можете опустить две строки распределения и освобождения локальных переменных, но ни в коем случае нельзя опускать установку границ стека BP, даже если аргументов и переменных в стеке нет.

Эти требования остаются теми же в случае, когда ExternFunc делает косвенные ссылки на оверлейные функции. Например, если OtherFunc вызывает оверлейные функции, но сама не является оверлейной, то ExternFunc должна быть FAR и также должна устанавливать границы стека.

В случае, когда ассемблерная подпрограмма не делает ни прямых, ни косвенных ссылок на оверлейные функции, то специальные требования отсутствуют; подпрограмма на языке Ассемблера может быть объявлена как NEAR. Она не обязана устанавливать границ стека.

Оверлейные подпрограммы на языке ассемблера не должны создавать переменные в кодовом сегменте, поскольку все изменения, внесенные в оверлейный кодовый сегмент, теряются при освобождении оверлея. Подобным же образом, указатели объектов, расположенных в оверлейных сегментах, не сохраняют достоверность после вызова других оверлеев, поскольку

201

Справочник по работе с DOS

программа управления оверлеями свободно перемещает и освобождает оверлейные кодовые сегменты в памяти.

Свопинг

Если в системе компьютера установлена дополнительная или расширенная память, вы можете сообщить программе управления оверлеев, что он должен использовать эту память при свопинге. В этом случае при удалении модуля из оверлейного буфера (когда туда требуется загрузить новый модуль, а буфер полон) программа управления оверлеями может поместить удаляемый модуль в эту память. При любой последующей загрузке этого модуля за счет того, что модуль перемещается в памяти, а не считывается с диска, экономится время.

В обоих случаях есть две возможности: программа управления оверлеями может либо обнаруживать наличие дополнительной или расширенной памяти самостоятельно и затем брать на себя управление этой памятью, либо использовать уже обнаруженную и распределенную часть такой памяти. В случае расширенной памяти обнаружение памяти не во всех случаях выполняется удачно, поскольку многие программы кэширования памяти и программы организации виртуального диска могут использовать эту память, не делая об этом никаких отметок. Чтобы избежать этих проблем, вы должны сообщить программе управления оверлеями начальный адрес расширенной памяти и какой участок ее можно безопасно использовать. Borland С++ предусматривает две функции, которые позволяют вам инициализировать расширенную и дополнительную

память — _OvrInitEms и _OvrInitExt.

Математические операции

Ниже рассматриваются возможности работы с числами с плавающей точкой и объясняется, как использовать математические операции с комплексными числами.

Операции ввода!вывода с плавающей точкой

Ввод вывод с плавающей точкой требует компоновки с подпрограммами преобразования, используемыми функциями printf и scanf. Чтобы уменьшить размер выполняемого файла, форматы с плавающей точкой автоматически не компонуются.

202

Справочник по работе с DOS

Однако такая компоновка автоматически выполняется при использовании в программе математической подпрограммы или получении адреса некоторого числа с плавающей точкой. Если не выполняется ни одно из этих действий не выполняется, то отсутствие форматов с плавающей точкой может дать в результате ошибку ввода вывода. Правильно оформить программу можно, например, следующим образом:

/* Подготовка к выводу чисел с плавающей точкой */ #include <stdio.h>

#pragma extref _floatconvert void main()

{ printf(*d = %f\n", 1.3);

}

Сопроцессор

Си работает с двумя числовыми типами: целыми (int, short, long и т.д.) и с плавающей точкой (float double и long double). Процессор вашего компьютера легко справляется с обработкой чисел целых типов, однако числа с плавающей точкой отнимают больше времени и усилий.

Семейство процессоров iAPx86 имеет сопутствующее ему семейство математических сопроцессоров. Мы будем обозначать все семейство математических сопроцессоров термином «сопроцессор». (В случае процессора 80487 вы имеете математический сопроцессор уже встроенным в основной.)

Процессор 80х87 представляет собой специальный аппаратно реализованный числовой процессор, который можно установить на вашем PC. Он служит для выполнения с большой скоростью команд с плавающей точкой. При большом количестве в вашей программе операций с плавающей точкой вам, безусловно, нужен сопроцессор. Блок центрального процессора в вашем компьютере осуществляет интерфейс с 80х87 по специальным шинам интерфейса.

Эмуляция платы 80х87

По умолчанию в Borland C++ устанавливается параметр генерации кода «эмуляция» (параметр компилятора режима командной строки f). Этот параметр предназначен для программ, которые могут вообще не иметь операций с плавающей точкой, а также для программ, которые должны выполняться и на

203

Справочник по работе с DOS

машинах, на которых сопроцессор 80х87 не установлен.

В случае параметра эмуляции компилятор генерирует код, как если бы сопроцессор присутствовал, но при компоновке подключает библиотеку эмуляции операций с плавающей точкой (EMU.LIB). При выполнении такой программы сопроцессор 80х87, если он установлен, будет использоваться. Если же во время выполнения процессора не окажется, то программа будет использовать специальное программное обеспечение, эмулирующее процессор 80х87.

Использование кода 80х87

Если вы планируете использовать вашу программу исключительно на машинах с установленным математическим сопроцессором 80х87, то можно сэкономить около 10К памяти программы, опустив из нее логику автоматического определения присутствия процессора 80х87 и эмулятора. Для этого следует просто выбрать параметр генерации кода операций с плавающей точкой при наличии сопроцессора 80х87 (или параметр компилятора режима командной строки f87). Borland C++ в этом случае скомпонует вашу программу с библиотекой FP87.LIB (вместо EMU.LIB).

Получение кода без операций с плавающей точкой

При отсутствии в программе операций с плавающей точкой вы можете сэкономить немного времени компиляции, выбрав значение параметра генерации операций с плавающей точкой None («отсутствуют») (или параметр компилятора командной строки f ). Тогда Borland C++ не будет выполнять компоновку ни с библиотекой EMU.LIB, ни с FP87.LIB, ни с MATHx.LIB.

Параметр быстрых вычислений с плавающей точкой

Borland C++ имеет параметр быстрых вычислений с плавающей точкой (параметр компилятора режима командной строки ff). Выключить этот параметр можно при помощи параметра командной строки ff . Его назначение состоит в выполнении некоторой оптимизации, противоречащей правильной семантике языка Си. Например:

double x;

x = (float)(3.5*x);

Для вычисления по обычным правилам x умножается на 3.5,

204

Справочник по работе с DOS

давая точность результата double, которая затем усекается до точности float, после чего x записывается как double. При использовании параметра быстрых вычислений с плавающей точкой произведение типа long double преобразуется непосредственно в double. Поскольку лишь очень немногие программы чувствительны к потере точности при преобразовании от более точного к менее точному типу с плавающей точкой, то данный параметр используется по умолчанию.

Переменная операционной среды 87

При построении программы с эмуляцией сопроцессора 80x87, которая устанавливается по умолчанию, ваша программа станет автоматически проверять наличие сопроцессора 80х87 и использовать его, если он установлен в машине.

Существует ряд ситуаций, в которых вам может понадобиться отменить режим автоматического определения наличия сопроцессора по умолчанию. Например, ваша собственная исполняющая система может иметь сопроцессор 80х87, но вам требуется проверить, будет ли программа работать так, как вы предполагали, в системе без сопроцессора. Либо ваша программа предназначена для работы в системе, совместимой с PC, но данная конкретная система возвращает логике автоматического определения наличия сопроцессора неверную информацию (либо при отсутствии сопроцессора 80х87 говорит, что он на месте, либо наоборот).

Borland C++ имеет параметр для переопределения логики определения наличия сопроцессора при загрузке программы. Этот параметр — соответствующая переменная операционной среды системы 87. Переменная операционной среды 87 устанавливается в ответ на подсказку DOS при помощи команды

SET:

C>SET 87=N

или

C>SET 87=Y

Ни с какой стороны знака равенства не должно быть пробелов. Установка переменной операционной среды 87 в N говорит загрузочному коду исполняющей системы о том, что вы

не хотите использовать сопроцессор 80х87 даже в том случае, если

205

Справочник по работе с DOS

он установлен в системе.

Установка переменной операционной среды в значение Y означает, что сопроцессор на месте и вы желаете, чтобы программа его использовала. Программист должен знать следующее: если установить 87=Y, а физически сопроцессор 80х87 в системе не установлен, то система «зависнет».

Если переменная операционной среды 87 была определена (с любым значением), и вы желаете сделать ее неопределенной, введите в ответ на подсказку DOS:

C>SET=

Непосредственно после знака равенства нажмите клавишу Enter, и переменная 87 станет неопределенной.

Регистры и сопроцессор 80х87

При работе с плавающей точкой вы должны учитывать два момента, связанных с использованием регистров:

В режиме эмуляции сопроцессора 80х87 циклический переход в регистрах, а также ряд других особенностей 80х87 не поддерживается.

Если вы смешиваете операции с плавающей точкой и встроенные коды на языке Ассемблера, то при использовании регистров следует должны принимать некоторые меры предосторожности. Это связано с тем, что набор регистров сопроцессора 80х87 перед вызовом функции в Borland C++ очищается. Вам может понадобиться извлечь из стека и сохранить регистры сопроцессора 80х87 до вызова функции, использующей сопроцессор, если вы не уверены, что свободных регистров достаточно.

Отмена обработки особых ситуаций для операций с плавающей точкой

По умолчанию программа Borland C++ в случае переполнения или деления на ноль в операциях с плавающей точкой аварийно прерывается. Вы можете замаскировать эти особые ситуации для операций с плавающей точкой, вызывая в main _control87 перед любой операцией с плавающей точкой.

206

Соседние файлы в предмете Программирование на C++