Программирование игр для Windows. Советы профессионала

       

Создание внешних ссылок


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

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

Синтаксис директивы EXTRN следующий:

EXTRN symbol: type, symbol: type,...

где symbol — имя переменной, a type — ее размер (например, BYTE, WORD, DWORD).

Директива EXTRN разрешает разместить переменную в вашем Си-коде и получить к ней доступ через параметры. Это имеет и обратную сторону: переменная, обозначенная как EXTRN означает, что она занимает текущий сегмент данных, адресуемых через регистр DS. Если вы все будете делать в модели SMALL или MEDIUM, то не стоит беспокоиться, если же вы работаете в модели LARGE, то никто не гарантирует, что вы получите доступ к вашей глобальной переменной, используя текущее значение регистра DS. Чтобы избежать этого, всегда применяйте модели SMALL и MEDIUM.

Давайте для примера напишем процедуру, которая складывает два целых числа и помещает результат в третье. Фокус заключается в том, что все эти величины будут глобальными и по отношению к ассемблерной процедуре - внешними. Листинг 2.6 демонстрирует код Си для этой программы, а в Листин­ге 2.7-показана ее реализация на ассемблере.

Листинг 2.6. Си-часть примера.

#include <stdio.h>

int first = 1, second = 2, third = 0;

// Это те числа, с которыми






// мы хотим работать

void main (void)

{

printf ("\nBefore adding third = %d\ third);

Add_Ext();                    

//вызываем ассемблерную процедуру

printf("\nAfter adding third = %d",third);

} // конец функции main

Листинг 2.7. Ассемблерная часть примера.

.MODEL MEDIUM                ; будем использовать MEDIUM модель

EXTRN first:WORD, second:WORD, third:WORD

.CODE                        ; начало кодового сегмента

_Add_Ext PROC FAR            ;процедура имеет тип FAR (дальняя)

mov AX, first                ; помещаем первое число в аккумулятор

add AX, second               ; прибавляем второе число

mov third, AX                ; помещаем результат в переменную third

_Add_Ext ENDP                ; конец процедуры

END                          ; конец кодового сегмента

Листинги 2.6 и 2.7 - это примеры использования внешних переменных first, second и third. Программа вызывает Add_Ext, которая складывает переменные first и second и сохраняет результат в third. Это подводит нас к теме возврата результатов обратно в программу на Си, которая вызывала ассемблерную процедуру.


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