Соглашения о вызове подпрограмм
В различных языках программирования используются различные правила вызова подпрограмм, и для совместимости с ними в языке Delphi существуют директивы register, stdcall, pascal и cdecl. Применение этих директив становится особенно актуальным при разработке динамически загружаемых библиотек, которые используются в программах, написанных на других языках программирования.
Чтобы разобраться с применением директив, обратимся к механизму вызова подпрограмм. Он основан на использовании стека.
Примечание.Стек- это область памяти, в которую данные помещаются в прямом порядке, а извлекаются в обратном, по аналогии с детской пирамидкой. Очередность работы с элементами в стеке обозначается термином LIFO (от англ. Last In, First Out - последним вошел, первым вышел).
Существует еще обычная очередность работы с элементами, обозначаемая термином FIFO (от англ. First In, First Out - первым вошел, первым вышел).
Для каждой программы на время работы создается свой стек. Через него передаются параметры подпрограмм и в нем же сохраняются адреса возврата из этих подпрограмм. Именно благодаря стеку подпрограммы могут вызывать друг друга, или даже рекурсивно сами себя.
Вызов подпрограммы состоит из «заталкивания» в стек всех аргументов и адреса следующей команды (для возврата к ней), а затем передачи управления на начало подпрограммы. По окончании работы подпрограммы из стека извлекается адрес возврата с передачей управления на этот адрес; одновременно с этим из стека выталкиваются аргументы. Происходит так называемая очистка стека. Это общая схема работы и у нее бывают разные реализации. В частности, аргументы могут помещаться в стек либо в прямом порядке (слева направо, как они перечислены в описании подпрограммы), либо в обратном порядке (справа налево), либо вообще, не через стек, а через свободные регистры процессора для повышения скорости работы. Кроме того, очистку стека может выполнять либо вызываемая подпрограмма, либо вызывающая программа. Выбор конкретного соглашения о вызове обеспечивают директивы register, pascal, cdecl и stdcall. Их смысл поясняет таблица 1.
Таблица 1. Соглашения о вызове подпрограмм.
Директива | Порядок занесения аргументов в стек | Кто отвечает за очистку стека | Передача аргументов через регистры |
register | Слева направо | Подпрограмма | Да |
pascal | Слева направо | Подпрограмма | Нет |
cdecl | Справа налево | Вызывающая программа | Нет |
stdcall | Справа налево | Подпрограмма | Нет |
Примечание.Директива register не означает, что все аргументы обязательно передаются через регистры процессора. Если число аргументов больше числа свободных регистров, то часть аргументов передается через стек.
Для процедур и функций динамически загружаемых библиотек следует выбирать соглашение о вызове stdcall:
procedure BubleSort(var Arr: array of Integer); stdcall;
procedure QuickSort(var Arr: array of Integer); stdcall;
Именно соглашение stdcall, изначально предназначенное для вызова подпрограмм операционной системы, лучше всего подходит для взаимодействия программ и библиотек, написанных на разных языках программирования. Все программы так или иначе используют функции операционной системы, следовательно они обязательно поддерживают соглашение stdcall.
Дата добавления: 2015-09-07; просмотров: 1101;