Интерфейс с программами и подпрограммами, написанными на разных языках программирования. Указатели на функции, страница 2

    }

  void swap(void *v[], int i, int j)

  { void *temp;

    temp = v[i];

    v[i] = v[j];

    v[j] = temp;

  }

2)  Вызов подпрограмм в том числе написанных на разных языках программирования.

Связь между подпрограммами можно осуществить тремя способами:

-  через общую зону (EXTERN - C, GLOBAL - Pascal, COMMON - Fortran)/

-  через регистры. Используется, если параметров не много, например в программах прерывания.

-  через стек.

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

Языки программирования принято разделять на процедурные (C, Pascal, Fortran, Basic) и непроцедурные (Lisp, Prolog, FORTH). В последних процедуры являются блоками программ, имеющие одну точку входа и одну точку выхода. Ассемблер одинаково легко можно использовать в качестве языка, способного использовать одинаково легко с обоими типами языков программирования.

Процедуры могут получать параметры из вызвавшей процедуры и передовать ей свои результаты с помощью следующих механизмов:

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

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

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

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

-  По имени, т.е. используют макроопределение, например директиву препроцессора C #define.

Для передачи параметров между языками высокого уровня существуют КОНВЕНЦИИ. Большинство языков программирования передают параметры вызывающей программе через СТЕК, а возвращаемое значение получают через определенный регистр. Например, в ПК возвращаемое значение получают через регистр AX (EAX) или через связку регистров DX:AX (EDX:EAX), если результаты не умещаются в одном регистре (например, при передаче адресов). В C значения, хранящиеся в этих регистрах или передаваемые в них устанавливать через макро _AX, _EAX, _DX, _EDX и т.д.

Конвенция PASCAL.

Этот способ применяется также в BASIC, FORTRAN, ADA, MODULA2 и состоит она в том, чтобы параметры помещать в стек в естественном поряде:

   Any_proc (int a,int b,int c,int d,int e)

запишется в виде:

         push a

         push b

         push c

         push d

         push e

         call Any_proc

Т.о. по окончании работы процедура Any_proc должна очистить стек до своего завершения. Сами параметры находятся в стеке в обратном порядке:

   Any_proc      proc

                 push   bp

                 push   bp,sp ; создать описание стека для

                              ; простого доступа к параметрам

   a             equ    [bp+12]

   b             equ    [bp+10]

   c             equ    [bp+8]

   d             equ    [bp+6]

   e             equ    [bp+4]

Завершение процедуры:

                 pop    bp

                 ret    10

   Any_proc      endp

Этот код в точности соответствует вызову

  Any_proc       proc  PASCAL a:word,b:word,c:word,d:word,e:word

Главный недостаток данной конвенции в сложности создания функций с переменным числом параметров (например, PRINTF), т.к. для этого сначала надо прочитать первый параметр, что сложно сделать.

Конвенция C.

Эта конвенция используется в языках C, C++, Prolog.

В этой конвенции параметры размещаются в стеке в обратном порядке:

         Any_proc (int a,int b,int c,int d,int e)

запишется в виде:

         push e

         push d

         push c

         push b

         push a

         call Any_proc

         add  sp,10   ; освободить стек

Процедура запишется так:

        Any_proc      proc

                 push   bp

                 push   bp,sp ; создать описание стека для

                              ; простого доступа к параметрам

   a             equ    [bp+4]

   b             equ    [bp+6]

   c             equ    [bp+8]

   d             equ    [bp+10]

   e             equ    [bp+12]

Завершение процедуры:

                 pop    bp

                 ret   

   Any_proc      endp

Здесь показан факт, что BP используется для хранения параметров и его нельзя менять.    

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

          push param2

          push param1

          call proc1

          call proc2

          add  sp,4

что эквивалентно

          proc1 (param1,param2);

          proc2 (param1,param2);

Это и позволяет компилятору C создавать самый компактный и быстрый код.

Известна также смешанная конвенция, когда расположение регистров в стеке аналогично C, но процедуры должны очистить стек по завершению работы сами, как в Pascal. Эта конвенция используется для системных функций WIN32 API.

Очень часто имена процедур изменяют, чтобы подчеркнуть используемую конвенцию. Например,

    call _someProc

подчеркивает, что вызов Ассемблера проводится в соответствии с конвенцией C.

Используемую конвенцию программирования можно заказать в Ассемблере, указав соответствующий идентификатор в описании процедур

        MODEL

И

        PROC.

В языке C можно заказать конвенцию C, PASCAL или передачу параметров через регистры, используя в турбо-языке адрес

   OPTION -> COMPILER -> ENTRY/EXIT CODE.