Многомодульные программы. Способ передачи параметров функциями языка Си, страница 4

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

Тип возвращаемого значения С++

Приемник результата

unsigned char

AX

char

AX

enum

AX

unsigned short

AX

short

AX

unsigned int

AX

int

AX

unsigned long

DX:AX

long

DX:AX

float

ST(0)

double

ST(0)

long double

ST(0)

near*

AX

far*

DX:AX

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

#include <iostream.h>

#include <string.h>

char *str = "Upper And Lower Case 12345";

char chngcs(char x)

{

asm     mov     al,x

asm     cmp     al,'A'

asm     jb         ext

asm     cmp     al,'z'

asm     ja         ext

asm     cmp     al,'Z'

asm     ja         met

asm     add      al,20h

asm     jmp      ext

met:

asm     cmp     al,'a'

asm     jb         ext

asm     sub       al,20h

ext:                 

}

void main()

{

char *ptr=str;

cout << "Before: " << str << "\n";

while(*ptr) *ptr++=chngcs(*ptr);

cout << " After: " << str << "\n";

}

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

model small

.stack   256

.data

filda    dw       1

.code

_main  proc

PUBLIC         _main

EXTRN          _cproc:proc

mov     ax,@data

mov     ds,ax

push    filda

mov     ax,76

push    ax

call      _cproc

add      sp,4

.exit     0

_main  endp

end      _main

#include <stdio.h>

void cproc(x,y)

int x;

int y;

{

printf("Rez %d %d\n",x,y);

getch();

}

В языке С++ компилятор добавляет к имени функции вместо подчерка символ «@» в начале идентификатора и описание параметров (начинающееся символами $q) в конце.

model small

.stack   256

.data

filda    dd       1.5

.code

_main  proc

PUBLIC         _main

EXTRN          @cproc$qif:proc

mov     ax,@data

mov     ds,ax

push    filda

mov     ax,76

push    ax

call      @cproc$qif

add      sp,6

.exit     0

_main  endp

end      _main

#include <iostream.h>

void     cproc(int x,float y)

{

cout << "Rez " << x << " " << y << "\n";

}

При этом для формирования имени функции берется одна буква от каждого спецификатора типа. Например, i – integer, f – float, d – double, p – указатель, u – unsigned, x – const, r – ссылка, c – char, l – long, s – short, v - void.

Если функция, написанная на ассемблере, является функцией членом класса, то имя такой функции начинается с символа «@» и имени класса. Остальная часть имени формируется по правилам описанным выше.

При вызове функции, написанной на ассемблере, из программы, написанной на Си++, в её тексте должен встречаться оператор EXTERN, описывающий прототип функции. Если в качестве типа будет указан тип «С», то функция на ассемблере можно оформлять стандартным образом не задумываясь об искажении имен.

Например.

#include <conio.h>

extern "C" void asmproc(char ch,unsigned x,unsigned y,unsigned kol);

void main(void)

{

clrscr();

asmproc('a',2,3,5);

asmproc('c',9,2,7);

}

.model small,c

.stack 256

.code

PUBLIC         asmproc

asmproc          proc     c near

ARG   chr:BYTE,x:WORD,y:WORD,kol:WORD

USES  ax,dx,cx,dx

mov     dh,byte ptr y   ; строка

mov     dl,byte ptr x    ; столбец

xor       bh,bh               ; видеостраница

mov     ah,2                 ; позиционирование курсора

int        10h

mov     ah,9                 ; вывод символа

mov     al,chr               ; символ

mov     bl,7                  ; атрибут

mov     cx,kol              ; мультипликатор

int        10h

ret

asmproc          endp

end