рефераты

рефераты

 
 
рефераты рефераты

Меню

Реферат: Turbo C++ Programer`s guide рефераты

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

Ниже приводится версия функции min (которая рассматривалась в разделе "обработка значений возврата" на стр.257 оригинала), использующая встроенное ассемблирование.

int min (int V1, int V2)

(*

asm (*

mov ax,V1

cmp ax,V2

jle minexit

mov ax,V2

*)

minexit:

return (_AX);

*)

Отметим схожесть данного кода с кодом настр.260 оригинала, который используетрасширение Turbo Assembler, связанное с заданием конкретного языка.

В качестве операторов встроенного ассемблирования допускается включать любые кодыопераций 8086. Существует четыре класса команд, позволяемых компилятором Turbo C++:

- обычные команды - стандартный набор кодов операций 8086

- строковые команды - специальные коды обработки строк

- команды перехода - различные коды операций перехода

- директивы ассемблирования - размещения и определения данных

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

Коды операций

___________________________________________________________

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

Мнемонические имена кодов операций                              Таблица 6.4

aaafdvtr  fpatan                      lsl

aadfeni  fprem                      mov

aamffroe**   fplan                          mul

aasfiadd  frndint   neg

adcficom  frstor                      nop

addficomp  fsave                      not

andfidiv  fscale                       or

boundfidifr  fsqrt                           out

callfild  fst                       pop

cbwfimul  fstcw                      popa

clcfincstp** fslenv                         popi

cldfinit  fstp                       push

clifist  fstsw                          pusha

cmcfistp  fsub                     pushf

cmpfisub  fsubp                      rcl

cwdfisubr  fsubr                        rcr

daafld  fsubrp                     ret

dasfld1  ftst                     rol

decfldcw  fweit                      ror

divfldenv  fxam                    sahf

enterfldl2e  fxch                        sal

f2xm1fldl2t  fxtract   sar

fabsfldlg2  fyl2x                          sbb

faddfldln2  fyl2xp1   shl

faddpfldpi  hlt                      shr

foldfldz  idiv                      smsw

fbstpfmul  imul                     stc

fchsfmulp  in                    std

fclexfnclex  inc                       sti

fcomfndisi  int                      sub

fcompfneni  into                     test

fcomppfninit  iret                         verr

fdecstp** fnop  lahf                         verw

fdisifnsave  lds                        wait

fdivfnstcw  lea                     xchg

fdivpfnstenv   leave                            xlat

fdivrfnstsw  les                       xor

При использовании средства встроенного ассемблирования в подпрограммах, эмулирующих операции с плавающей точкой (опцияTCC -O), коды операции, помеченные **, не поддерживаются.

При использовании в операторах встроенного ассемблирования мнемонических команд 80186 необходимо включать опцию командной строки -1. Тогда компилятор включит в генерируемый им ассемблерный код соответствующие операторы, в результате чего Turbo Assembler будет ожидать появление данныхмнемоническихимен.При использовании предыдущих версий ассемблера эти мнемонические имена могут не поддерживаться.

Строковые команды

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

Строковые команды                      Таблица 6.5

capslasw movsb

capsblods movsw

capswlodsb outs

laslodsw outsb

lasbmovs

outswstos

scasstosb

scasbstosw

scasw

Префиксы ________________________ __________________________________
Допустимы следующие префиксы:

lock   rep reperepnerepnzrepz

Команды перехода

Команды перехода рассматриваются отдельно. Поскольку метка не может быть включена в саму команду, переходы выполняются к меткам С (см. раздел "Использование команд перехода и меток" на стр.274 оригинала). В следующей таблице перечисленыдопустимые команды перехода:

Команды перехода                       Таблица 6.6

jajge jnc jnp

jaejl jne jns

jbjle jng jnx

jbejmp jnge jo

jcjna jnl jp

jcxzjnae jnle jpe

jejnb jno jpo

jgjnbe

js

jz

loop

loope

loopae

loopnz

loopz

Директивы ассемблирования

В операторах встроенного ассемблирования Turbo C++ допустимы следующие директивы:

db   dd  dw extra

Ссылки из операторов встроенного ассемблирования к данным и функциям

В операторах asm допускается использовать символические имена С; Turbo C++ автоматически преобразовывает их в соответствующие операнды языка ассемблера и вставляет перед этими именами символ подчеркивания. Допускается использование любых символических имен, включая автоматически распределяемые (локальные)переменные, регистровые переменные и параметры функций.

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

Как только ассемблер встречает во время лексического анализа операндов встроенного ассемблера идентификатор, просматривается таблица символических имен С. Имена регистров 8086 из этого поиска исключаются. Имена регистров могут быть набраны какзаглавными, так и строчными буквами.

Встроенное ассемблирование и регистровые переменные

Встроенный ассемблерный код может свободно использовать рабочие регистры SIи DI.При использовании во встроенном ассемблерномкоде регистров SI и DI компилятор не станет распределять их для регистровых переменных.

Встроенное ассемблирование, смещения и переопределение размера

___________________________________________________________

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

Однако, может оказаться необходимым включение в ассемблерную команду соответствующего WORD PTR, BYTE PTR, или любого другого переопределения размера. Переопределение DWORD PTR требуется задавать в командах LES или косвенного дальнего вызова.

Использование компонентов структур С

___________________________________________________________

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

struct myStruct (*

int a_a;

int a_b;

int a_c;

*) myA;

myfunc ()

(*

...

asm (*mov  ax, myA.a_b

mov  bx, [di].a_b

*)

...

*)

Мы объявили тип структуры с именем myStruct с тремя компонентами,a_a, a_b и a_c; мы также объявили переменную myA типа myStruct. Первый оператор встроенного ассемблирования пересылает значение из myA.a_b в регистрAX. Второй оператор пересылает значение по адресу [di]+смещение(a_c) в регистр BX(он беретадрес,хранимый в DI, и складывает со смещениемa_c относительно начала myStruct.) В такой последовательностиэти ассемблерные операторы образуют следующий ассемблерный код:

mov  ax, DGROUP : myA+2

mov  bx, [di+4]

Для чего это может понадобиться? Загрузив регистр (например, DI) адресом структуры типа myStruct вы можетеиспользовать имена компонентов для непосредственных ссылок к этим компонентам. Фактически имя компонента может быть использовано везде, где в качестве операнда ассемблерного операторадопустима числовая константа.

Компоненту структуры обязательно должна предшествовать точка (.), котораясообщает, чтоданноеимя -это имя компонента структуры, а не обычное символическое имя С. Имена компонентов в ассемблерном виде на выходе компилятора заменяются числовыми смещениями (числовое значение a_c равно 4), аинформация о типе теряется. Таким образом, компоненты структуры могут использоваться в ассемблерных операторах как константы времени компиляции.

Однако,здесьсуществует одно                       ограничение.                  Еслидве

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

asm  mov  bx,[di].(struct tm)tm_hour

Использование команд перехода и меток

___________________________________________________________

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

В следующем примере кода переход выполняется к метке C goto a.

int               x()

(*

a:            /* это метка команды C goto  "a"  */

...

asm  jmp  a  /* переход к метке"a" */

...

*)

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

Функции прерывания

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

int int#

где int# это число от 0h до FFh. Когда встречается данная команда, компьютер сохраняет кодовый сегмент (CS), указатель команд (IP) и состояния флагов, затем запрещает прерывания и выполняет дальний переход по адресу, на который указывает соответствующий вектор прерывания. Например, часто встречается прерывание

int 21h

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

Для того, чтобы написать в Turbo C++ обработчик прерывания, вы должны определить функцию с типом interrupt; более конкретно, она может выглядеть следующим образом:

void interrupt myhandler(bp, di, si, ds, es, dx,

cx, bx, ax, ip, cs, flags, ...);

Как можно заметить, все регистры передаютсяв качестве параметров, что позволяет использовать и модифицировать их в вашей программе, не прибегая к рассмотренным выше в данной главе псевдопеременным. Допускается также передачаобработчику прерываний дополнительных параметров (flags,...); последние должны иметь соответствующие определения.

Функция типа interrupt автоматически сохраняет (помимо SI, DI и BP) регистры от AX до DX и DS. Эти же регистры при выходе из обработчика прерывания восстанавливаются.

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

Функция прерывания может модифицировать передаваемые ей параметры. Изменение объявленных параметров приведет к модификации соответствующего регистра при выходе из обработчика прерывания. Это свойство может оказаться полезным, когда обработчик прерывания используется как служебнаяфункция пользователя, какэто происходит вслучаеслужебной функции DOS INT

21. Кроме того, обратите внимание на то, что функция прерывания выполняет выход с помощью команды IRET (возврата из прерывания).

Итак, в каких случаях может понадобиться написать собственный обработчик прерываний? Делов том, что так работает большинство резидентных программ. Они инсталлируются какобработчики прерываний. Тем самым, при выполнении некоторого периодического или специального действия (тактовом сигнале часов, нажатии клавиши и т.д.) происходит обращение к соответствующемуобработчику прерывания и соответствующие действия. Затем управление возвращается программе, при выполнении которой встретилось данное прерывание.

Практические примеры программ низкого уровня

Мы уже рассмотрели несколько примеров обращений к функциям низкого уровня из С-программы; рассмотрим еще несколько таких практических примеров. Начнем с обработчика прерывания, который выполняет некоторые безвредные, но ощутимые (в данном случае слышимые) действия: при его вызове раздается звуковой сигнал.

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

#include   <dos.h>

void interrupt mybeep(unsigned bp, unsigned di, unsigned si, unsigned ds, unsigned es, unsigned dx, unsigned cx, unsigned bx, unsigned ax)

(*

int             i, j;

char   originalbits, bits;

unsigned char  bcount = ax >> 8;

/* прием текущих установок управляющего порта */

bits = originalbits = inportb(0x61);

for (i = 0; i <= bcount; i++) (

/* временное выключение динамика */

outportb(0x61, bits & 0xfc);

for (j = 0; j <= 100; j++)

; /* пустой оператор */

/* теперь динамик на некоторое время включается */

outportb(0x61, bits \! 2);

for (j = 0; j <= 100; j++)

; /* еще один пустой оператор */

)

/* восстановление установок управляющего порта */

outportb(0x61, originalbits);

*)

Затем напишем функцию, которая будет инсталлировать данный обработчик прерываний. Ей передается адрес и номер обработчика (от 0 до 255 или от 0x00 до 0xFF).

void install(void interrupt (*faddr)(), int inum)

(*

setvect(inum, faddr);

*)

И наконец, вызовем для проверки написанную вами сигналящую подпрограмму. Это сделает следующая функция:

void testbeep(unsigned char bcount, int inum)

(*

_AH = bcount;

geninterrupt(inum);

*)

Функция main может иметь вид:

main()

(*

char ch;

install(mybeep,10);

testbeep(3,10);

ch = getch();

*)

Вы можете также сохранить исходный вектор прерывания и восстановить его при выходе из главной программы. Для этого служат функции getvect и setvect.

Глава 7Сообщения об ошибках

Turbo C++ различает две категории ошибок: времени выполнения и времени компиляции. Сообщения об ошибках времени выполнения выдаются непосредственно при их обнаружении. Сообщения об ошибках времени компиляции делятся на три категории: фатальные ошибки, не-фатальные ошибки и предупреждения. Более подробно они описаны, начиная со стр.283 оригинала.

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

------------------------------------------------------------

Обобщенное имя Фактическое имя или значение в данном руководствевыводимое на экран

------------------------------------------------------------ аргументАргумент командной строки или иной аргумент классИмя класса

полеСсылка на поле

имя_файлаИмя файла (с расширением или без)

группа Имя группы

идентификаторИдентификатор (имя переменной или другой) языкНазвание языка программирования компонентИмя компонента данных или функции компонента сообщениеСтрока сообщения

модуль Имя модуля

числоФактическое число

опцияОпция командной строки или другая опция параметрИмя параметры

сегментИмя сегмента

спецификаторСпецификатор типа символическое_имяСимволическое имя XXXXh4-значное шестнадцатиричное число,

за которым следует h

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

Например, если у вас имеется функция С++ goforit, то фактически вы можете получить сообщение об ошибке

goforit must be declared with no arguments

Для того, чтобы найти описание данного сообщения в этой главе, искать следует сообщение

Страницы: 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