Turbo Assembler 3.0. Руководство пользователя

         

Вызов из Турбо Ассемблера функции Borland C++


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

Давайте рассмотрим пример программы на Ассемблере, которая вызывает функцию Borland C++, чтобы выполнить вычисления с плава- ющей точкой. Фактически в данном примере функция Borland C++ пе- редает последовательность целых чисел другой функции Турбо Ас- семблера, которая суммирует числа и в свою очередь вызывает другую функцию Borland C++ для выполнения вычислений с плавающей точкой (вычисление среднего значения).

Часть программы CALCAVG.CPP, реализованная на С++ (CALCAVG.CPP), выглядит следующим образом:

#include <stdio.h> extern float Average(int far * ValuePtr, int NumberOfValues); #define NUMBER_OF_TEST_VALUES 10 int TestValues(NUMBER_OF_TEST_VALUES) = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

main() { printf("Среднее арифметическое равно: %f\n", Average(TestValues, NUMBER_OF_TEST_VALUES)); } float IntDivide(int Divedent, int Divisor) } return( (float) Divident / (float) Divisor );

}

а часть программы на Ассемблере (AVERAGE.ASM) имеет вид:

; ; Вызываемая из С++ функция с малой моделью памяти, ; которая возвращает среднее арифметическое последова- ; тельности целых чисел. Для выполнения завершающего ; деления вызывает функцию С++ IntDivide(). ; ; Прототип функции: ; extern float Average(int far * ValuePtr, ; int NumberOfValues); ; ; Ввод: ; int far * ValuePtr: ; массив значений для ; ; вычисления среднего ; int NumberOfValues: ; число значений для ; ; вычисления среднего .MODEL SMALL EXTRN _IntDivide:PROC .CODE PUBLIC _Average _Average PROC push bp mov bp,sp les bx,[bp+4] ; ES:BX указывает на ; массив значений mov cx,[bp+8] ; число значений, для ; которых нужно ; вычислить среднее mov ax,0 AverageLoop: add ax,es:[bx] ; прибавить текущее ; значение add ax,2 ; ссылка на следующее ; значение loop AverageLoop push WORD PTR [bp+8] ; получить снова число ; значений, переданных ; в функцию IntDivide ; в правом параметре push ax ; передать сумму в ; левом параметре call _IntDivide ; вычислить среднее ; значение с плавающей ; точкой add sp,4 ; отбросить параметры pop bp ret ; среднее значение в ; регистре вершины ; стека сопроцессора ; 8087

_Average ENDP END

Основная функция (main) на языке С++ передает указатель на массив целых чисел TestValues и длину массива в функцию на Ас- семблере Average. Эта функция вычисляет сумму целых чисел, а за- тем передает эту сумму и число значений в функцию С++ IntDivide. Функция IntDivide приводит сумму и число значений к типу с плава- ющей точкой и вычисляет среднее значение (делая это с помощью од- ной строки на С++, в то время как на Ассемблере для этого потре- бовалось бы несколько строк). Функция IntDivide возвращает сред- нее значение (Average) в регистре вершины стека сопроцессора 8087 и передает управление обратно основной функции.

Программы CALCAVG.CPP и AVERAGE.ASM можно скомпилировать и скомпоновать в выполняемую программу CALCAVG.EXE с помощью коман- ды:

bcc calcavg.cpp average.asm

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

Пользуясь преимуществами расширений, обеспечивающих незави- симость Турбо Ассемблера от языка, ассемблерный код из предыдуще- го примера можно записать более сжато (CONSISE.ASM):

.MODEL small,C EXTRN C IntDivide:PROC .CODE PUBLIC C Average Average PROC C ValuePtr:DWORD, NumberOfValues:WORD les bx,ValuePtr mov cx,NumberOfValues mov ax,0 AverageLoop: add ax,es:[bx] add bx,2 ;установить указатель ;на следующее значение loop AverageLoop call _IntDivide C,ax,NumberOfValues ret Average ENDP END

Содержание раздела