Реферат: Turbo C++ Programer`s guide
Подпрограммы управления палитрой
в случае CGA
Поскольку палитра CGA является предопределенной,
подпрограмму setallpaletteиспользовать в данном случае нельзя. Также не следует
использовать setpalette(индекс, фактический _цвет), за исключением индекс=0.
(Этоальтернативный способ установки фонового цвета CGA равным
фактическому_цвету).
Управление цветом для EGA и
VGA
В случае EGA палитрасодержит 16 элементов из общего
количества 64 возможных цветов, причем каждый из элементов палитры можетбыть
задан пользователем. Доступ к текущей палитре выполняется через getpalette,
которая заполняет структуру, включающую всебя размер палитры (16)
имассивфактических элементов палитры ("аппаратные номера цветов",
хранимые в палитре). Элементы палитры можно изменять как по отдельностипри
помощи setpalette, либо все сразу через setallpalette.
Палитра EGA по умолчанию соответствует 16 цветам CGA,
которые были даны впредыдущей таблице цветов: черный равен элементу 0, голубой
равен элементу 1, ... , белый равен элементу 15. В graphics.h определены
константы, которые содержат соответствующие цветам аппаратные значения: это
EGA_BLACK, EGA_WHITE и т.д.Эти значения могут быть также получены через
getpalette.
Подпрограмма setbkcolor(цвет) на EGAработает несколько
иначе, чем на CGA. На EGA setbkcolor копирует фактическое значение цвета,
хранящееся в элементе #цвет, в элемент #0.
Что касается цветов, то драйвер VGA работает фактическитак
же, как и драйвер EGA; он просто имеет более высокое разрешение (и меньшие по
размеру пиксели).
Обработка ошибок в графическом
режиме
Ниже приводитсякраткий обзорфункций обработки
ошибок в графическом режиме:
grapherrormsg Возвращает строку с сообщением об ошибке для
заданного кода ошибки.
graphresult Возвращает код ошибки для последней
графической операции, в которой встретилась ошибка.
Если ошибка произошла при вызове графической библиотечной функции
(например,не найден шрифт, запрошенный функцией settextstyle), устанавливается
внутренний код ошибки. Доступ к коду ошибки для последней графической операции,
сообщившей об ошибке, выполняется при помощи graphresult. Определены следующие
коды возврата ошибки:
-----------------------------------------------------------
Код
Константа Соответствующая строка
ошибки графической_ошибки с
сообщением об ошибке
0 grOk No error Нет ошибки
-1 grNoInitGraph (BGI) graphics not installed (use
initgraph)
(BGI) графика
не инсталирована
(используйте initgraph)
-2 grNotDetected Graphics hardware not detected
Графическое аппаратное обеспечение
не обнаружено
-3 grFileNotFound Device driver file not found Не
найден файл драйвера устройства
-4 grInvalidDriver Invalid device driver file
Неверный файл драйвера устройства
-5 grNoLoadMem Not enough memory to load driver Не
хватает памяти для загрузки
драйвера
-6 grNoScanMem Out of memory in scan fill Кончилась
память при сканирующем
заполнении
-7 grNofloodMem Out of memory in flood fill
Кончилась память при лавинном
заполнении
-8
grFontNotFound Font file not found
Файл шрифта не найден
-9 grNoFontMem Not enough memory to load font Не
хватает памяти для загрузки
шрифта
-10 grInvalidMode Invalid graphics mode for selrcted
driver
Недопустимый
графический режим для выбранного драйвера
-11 grError Graphics error Графическая ошибка
-12 grIOerror Graphics I/O error Графическая ошибка
ввода/вывода
-13 grInvalidFont Invalid font file Неверный файл
шрифта
-14 grInvalidFontNum Invalid font number Неверный
номер шрифта
-15 grInvalidDeviceNum Invalid device number
Неверный номер устройства
-16 grInvalidVersion Invalid version of file
Неправильная версия файла
-----------------------------------------------------------
Вызов grapherrormsg(graphresult()) возвращает
строку сообщения об ошибке из вышеприведенной таблицы.
Код возврата ошибки накапливается, изменяясь только когда
графическая функция сообщает об ошибке. Код возврата ошибки сбрасывается в 0
только при успешном выполнении initgraph, либо при вызове graphresult. Таким
образом, если вы хотите знать, какая графическая функция возвратила ошибку,
нужно хранить значение graphresult во временной переменной и затем проверять
ее.
Функции запроса состояния
Ниже приводится краткое изложение функций запроса
состояния графического режима:
getarccoords Возвращает информацию о координатах, заданных
в последнем вызове arc или ellipse.
getaspectratio Возвращает коэффициент сжатия для графического экрана.
getbkcolor Возвращает
текущий цвет фона.
getcolor Возвращает
текущий цвет вычерчивания.
getdrivername Возвращает имя текущего графического
драйвера.
getfillpattern Возвращает шаблон заполнения, определяемый пользователем.
getfillsettings
Возвращает информацию о текущем шаблоне
и цвете заполнения.
getgraphmode Возвращает
текущий графический режим.
getlinesettings Возвращает текущие стиль, шаблон и толщину линии
getmaxcolor Возвращает максимально допустимое на текущий
момент значение пикселя.
getmaxmode Возвращает максимально допустимый номер режима
для текущего драйвера.
getmaxx Возвращает
текущее разрешение по оси x.
getmaxy Возвращает
текущее разрешение по оси y.
getmodename Возвращает
имя данного режима драйвера.
getmoderange Возвращает
диапазон режимов для данного
драйвера.
getpalette Возвращает
текущую палитру и ее размер.
getpixel Возвращает
цвет пикселя в (x,y).
gettextsettings Возвращает текущий шрифт,
направление, размер и способ выравнивания текста.
getviewsettings Возвращает информацию о текущем
графическом окне.
getx Возвращает
координату x текущей позиции (CP).
gety Возвращает
координату y текущей позиции (CP).
В каждой из категорий графических функций Turbo C++
имеется хотя бы одна функция запроса состояния. Эти функцииупоминались при
рассмотрении соответствующих категорий и также рассматриваются здесьотдельно.
Каждая из графических функций запроса состояния Turbo C++ имеет имя вида
"getчто-то" (за исключением категории функций обработки ошибок). Некоторые
из них не принимают никаких аргументов ивозвращают единственное значение,
представляющее собой искомую информацию; прочие берут указатель структуры,
определяемой в graphics.h, заполняют эту структуру соответствующей информацией
и не возвращают никаких значений.
Функциями запроса состояния категории
управленияграфической системы являются getgraphmode, getmaxmode и getmoderange.
Первая из них возвращает целое число, определяющее текущийграфический драйвер и
режим, вторая возвращает максимальный номер режима для этого драйвера, а третья
возвращает диапазон режимов, поддерживаемых данным графическим драйвером.
getmaxx и getmaxy возвращают соответственно максимальные экранные координаты x
и y для текущего графического режима.
Функциями запроса состояниякатегории вычерчивания и
заполнения являются getarccoords, getaspectratio, getfillpattern и
getlinesettings. getarccoords заполняет структуру, содержащуу координаты,
которые использовались при последнем вызове функций arc или ellipse;
getaspectratio сообщает текущийкоэффициент сжатия, используемый
графическойсистемой для того, чтобы окружности выглядели круглыми.
getfillpatternвозвращает текущий определяемыйпользователем шаблон заполнения.
getfillsettings заполняет некоторуюструктуру текущим шаюлоном и цветом
заполнения. getlinesettings заполняет структуру текущим стилем линии(сплошная,
пунктир и т.д.), толщиной (обычнаяили увеличенная), а также шаблоном линии.
Функциями запроса состояниякатегории манипулирования
графическим окном являются getviewsettings, getx, gety и getpixel. После того,
как графическое окно определено, вы можете найтиего абсолютные экранные
координаты ивыяснить состояние режима отсечки, вызвав getwiewsettings, которая
заполняет соответствующей информацией некоторую структуру. getx и gety возвращают
(относительно графическогоокна) x- и y-координаты текущей позиции. getpixel
возвращает цвет указанного пикселя.
Функция запросасостояния категориивывода текста в
графическом режиме имеется только одна - gettextsettings. Эта функция заполняет
структуруинформацией отекущем символьном шрифте, направлении вывода текста (по
горизонтали или по вертикали)6 коэффициенте увеличениясимволов, а также виде
выравнивания (как для горизонтально, так идля вертикально-ориентированных
текстов).
Функциями запроса состоянии категорииуправления цветом
являются getbkcolor,возвращающая текущий цвет фона, getcolor, возвращающая
текущий цвет вычерчивания и getpalette,заполняющая структуру, которая включаетв
себя размер текущей палитры и ее содержимое. getmaxcolor возвращает максимально
допустимое значение пикселя для текущего графического драйвера и режима (размер
палитры -1).
И наконец, getmodename и getdrivername возвращаютимя заданного режима
драйвера и имя текущего графического драйвера, соответственно.
Глава 6
Интерфейс с языком ассемблера
В данной главе рассказывается, как написать
ассемблерный код, который будет хорошо работать с Turbo C++. Предполагается,
что вы знаете, как пишутсяподпрограммы на языке ассемблера икак определяются
сегменты, константы данных и т. д. Если вы не знакомы с этими концепциями,
почитайте руководство по Turbo Assembler, особенно главу "Интерфейс Turbo
Assembler с Turbo C" в Руководстве пользователя. TurboAssembler версии
2.0включает несколько средств, делающих интерфейс с Turbo C++ более простым и
прозрачным для программиста.
Смешанное программирование
Turbo C++ упрощает вызов из С-программ подпрограмм,
написанных на языке ассемблера, и наоборот, вызов из ассемблерных программ
подпрограмм на С. В данном разделе показано, насколько простинтерфейс между
Turbo C++ и ассемблером; также приводится информация, помогающая на практике
осуществить такой интерфейс.
Последовательности передачи
параметров
Turbo C++ поддерживаетдва метода передачи параметров функции. Один из них
является стандартным методом С, который мы рассмотрим первым; второй метод
заимствован из Паскаля.
Последовательность передачи
параметров в С
Предположим, вы объявили
следующий прототип функции:
void funca(int p1, int p2, long
p3);
По умолчанию Turbo C++ использует последовательность передачи параметров
С, которая также называется соглашением о связях С. При вызове этой
функции(funca) параметры помещаютсяв стек в последовательности справа-налево
(p3,p2,p1), послечего в стек помещается адрес возврата. Таким образом, в случае
вызова
main()
(*
int i,j;
long k;
...
i = 5; j = 7;
k = 0x1407AA;
funca(i,j,k);
...
*)
то стек (непосредственно перед помещением в него адреса возврата) будет
выглядеть следующим образом:
sp + 06: 0014
sp + 04: 07AA
k = p3
sp + 02: 0007
j = p2
sp: 0005 i = p1
Вызываемой подпрограмме не требуется точно знать,
сколько параметров помещено в стек. Она просто предполагает, что все нужные ей
параметры находятся в стеке.
Кроме того - что очень важно - вызываемая подпрограмма не
должна снимать параметры со стека. Почему? Дело в том, что это сделает
вызывающая программа. Например, приведенная выше функция в ассемблерном виде,
получаемом компилятором из исходного кода на С, будет выглядеть следующим
образом:
mov WORD PTR [bp-8],5;установка
i =5
mov WORD PTR [bp-6],7;установка
j = 7
mov WORD PTR [bp-2],0014h;установка
k = 0x1407AA
mov WORD PTR [bp-4],07AAh
push WORD PTR [bp-2];помещение
в стек старшего слова k
push WORD PTR [bp-4];помещение
в стек младшего слова k
push WORD PTR [bp-6];помещение
в стек j
push WORD PTR [bp-8];помещение
в стек i
call NEAR PTR funca
;вызов funca (помещение в стек
;адреса
возврата)
add sp,8;настройка стека
Обратите внимание на последнюю команду, add sp,8. К
этому моменту компилятору известно, сколько параметров было помещено в стек;
компилятор также знает, что адрес возврата был помещен в стек при вызове funca
и уже был снят оттуда командой ret в конце funca.
Последовательность передачи
параметров Паскаля
Другим методом передачи параметров является
стандартный метод передачи параметров Паскаля (называемый также соглашением о
связях Паскаля). Это не значит, что вы можете вызывать из TurboC++ функции
Turbo Pascal. Это невозможно. Если funca объявлена как
void pascal funca(int p1, int
p2, long p3);
то при вызове этой функции параметры помещаются в стек в
последовательности слева-направо (p1,p2,p3), после чего в стек помещается адрес
возврата. Таким образом, при вызове:
main()
(*
int i,j;
long k;
...
i = 5; j = 7;
k = 0x1407AA;
funca(i,j,k);
...
*)
то стек (непосредственно перед помещением в него адреса возврата) будет
выглядеть следующим образом:
sp + 06: 0005
i = p1
sp + 04: 0007
j = p2
sp + 02: 0014
sp: 07AA k = p3
Итак, в чем здесь различие? Дело в том, что помимо
изменения очередности помещения параметров в стек, последовательность передачи
параметров Паскаля предполагает, что вызываемая функция (funca) знает, сколько
параметров будет ей передано и соответственно настраиваетстек. Другимисловами,
теперь в ассемблированном виде данная функция будет иметь вид:
push WORD PTR [bp-8];помещение
в стек i
push WORD PTR [bp-6];помещение
в стек j
push WORD PTR [bp-2];помещение
в стек старшего слова k
push WORD PTR [bp-4];помещение
в стек младшего слова k
call NEAR PTR funca
;вызов funca (помещение в стек
;адреса возврата)
Отметим, что теперь после вызова отсутствует командаadd sp,8. Вместо нее
funca использует при окончании команду ret 8, при помощи которой очищает стек
перед возвратом к main.
По умолчанию все функции, создаваемые в Turbo C++,
используют способ передачи параметров С. Исключение делается при наличии
опциикомпилятора -p (опция Pascal в диалоговомполе Code Generation); в этом
случае все функции используют метод передачи параметров Паскаля. Тем не менее,
вы можете задать для любой функции метод передачи параметров С при помощи
модификатора cdecl:
void cdeclfunca(int p1, int p2,
long p3);
Данное объявление переопределит директиву компилятора - p.
И однако, почему может возникнуть необходимость
использовать соглашение о связях Паскаля вообще? Для этого есть две главных
причины.
- Вам может понадобиться вызывать существующие
подпрограммы на языке ассемблера, использующие соглашение о связях Паскаля.
- Получаемый в таком случае код несколько меньше по
размеру, поскольку в этом случае не требуется в конце выполнять очистку стека.
Однако, использование соглашения о связях Паскаля может вызвать некоторые
проблемы.
Прежде всего, соглашение о связях Паскаля дает меньше
возможностей,чем для С. Вы не можете передавать переменное число параметров
(как этодопускается всоглашении С), поскольку вызываемая подпрограмма должна
знать число передаваемых ей параметров и соответственнымобразом настроить стек.
Передача большего или меньшего числа параметроввызывает серьезные проблемы,
тогда как в случае соглашения С ничего особенного в такихслучаях не происходит
(кроме, возможно, того, что программа даст неправильный ответ).
Во-вторых, при использовании опции компилятора вы
обязательно включить файлы заголовка длявсех вызываемых вашей программой
стандартных функций С. Почему? Дело в том, что в противном случае Turbo C++ будет
использовать для каждой из этих функций соглашение о связях (и именах) - и ваша
программа не будет компоноваться.
В файле заголовка каждая из этих функций объявлена как
cdecl, поэтому включение файловзаголовка заставит компилятор использовать для
этих функций соглашение С.
Резюме:если вы собираетесь использовать вС-программе
соглашение освязяхПаскаля, не забывайте о необходимости использовать прототипы
функций везде, где это возможно, а каждую функцию явно объявляйте pascal или
cdecl. Полезно также разрешить выдачу сообщения "Function call with no
prototype" ("вызов функции без прототипа"), чтобы гарантировать
наличие прототипов всех функций.
Подготовка к вызову .ASM из Turbo
C++
При написании подпрограмм на языке ассемблера нужно
принимать во внимание определенные соглашения для того, чтобы (1) обеспечить
компоновщик нужной ему информацией и (2) обеспечить соответствие формата файла
и модели памяти, используемой в программе на С. Упрощенные сегментные директивы
Обычно модули на языке ассемблера состоят из трех
разделов: кода, инициализированных данных и неинициализированных данных. Каждый
из этих типов информации организован в отдельный сегмент с использованием
определенных имен, которые зависят от используемой в вашей С-программе модели
памяти.
Turbo Assembler (TASM) предлагает вам три упрощенных сегментных директивы
(.CODE, .DATA и .DATA?), которыемогут быть использованыпри определении этих
сегментов. Они говорят компилятору о необходимостииспользовать имена сегментов
по умолчанию для модели памяти, заданной вами при помощи директивы .MODEL.
Например, если ваша программа на С использует модель памяти small, вы можете
организовать каждый ассемблерный модуль с упрощенными сегментными
директивами,как показано в следующей таблице:
-----------------------------------------------------------
.MODEL SMALL
.CODE
...кодовый сегмент...
.DATA
...сегмент инициализированных
данных...
.DATA?
...сегмент
неинициализированных данных...
Стандартные сегментные директивы
В некоторых случаях вам может понадобиться использовать другие имена
сегментов, нежели те, что являются умолчаниямидля данной модели памяти. Для
этого вы должны использовать стандартные сегментные директивы, как показано в
Таблице 6.1.
Формат файла языка ассемблера Таблица
6.1
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
|