
    Листинг 17.6.  TIMER.Н (заголовочный файл для функции Timer()) 

    1:   // timer.h -- Заголовочный файл для timer.срр 
    2: 
    3:   extern "С"  { 
    4: 
    5:     long Timer(); 
    6: 
    7:    } 

    Прототипы внешних функций в программах на C++ обычно объявляются внутри 
директивы extern "С" { }. Это предотвращает процесс так называемого 
модифицирования имен, согласно которому C++ преобразует имена функций в 
уникальные строки, которые позволяют стандартным компоновщикам обрабатывать 
объектно-ориентированный код. Например, функция с именем TimerO будет иметь 
имя @Timer$gv. Подобные имена затруднительны для чтения, и, вероятно, лучше 
пользоваться модифицированными именами внешних функций в ассемблерных модулях. 
(Компиляторы ANSI С не модифицируют имена функций, так что этот совет касается 
только программ на C++.) 

   СОВЕТ

    Если вам необходимо воспользоваться модифицированными именами (например, 
если вы хотите поддерживать и использовать функцию, написанную и на ассемблере 
и на C++), напишите пустую функцию без операторов и скомпилируйте ее с опцией 
-S для получения ассемблерного файла с модифицированными именами. 
Воспользуйтесь этим файлом как оболочкой, которую следует наполнить 
инструкциями вашей настоящей функции. 

    Далее следует ассемблерный модуль, в котором находятся выполняемые 
инструкции для внешней функции Timer(). В листинге 17.7 приводится реализация 
функции Timer() с помощью синтаксиса идеального режима TASM. 

    Листинг 17.7. TIMER.ASM (реализация функции Timer() во внешнем ассемблерном модуле) 

    1:	IDEAL 
    2:	MODEL small 
    3: 
    4:	CODESEG 
    5:	PUBLIC _Timer 
    6: 
    7:	PROC _Timer 
    8:	xor ax, ax ; Задать ах равным 0000 
    9:	mov es, ax ; Задать es равным 0000 
    10:	mov di, 0046cH ; Задать di равным 046С 
    11:	mov ax, [WORD PTR es:di] ; Взять младший байт timer 
    12:	mov dx, [WORD PTR es:di+2] ; Взять старший байт	timer 
    13:	ret ; Вернуться в место вызова 
    14:	ENDP 
    15: 
    16:	END 

    В строке 2 демонстрируется одна важная деталь — выбор модели памяти. Вы 
должны использовать одну и ту же модель памяти во внешнем модуле и в главной 
программе (см. главу 19). Внутри сегмента кода (который начинается ключевым 
словом CODESEG в строке 4) объявляется имя внешней функции с помощью директивы 
PUBLIC. Предварите глобальное имя символом подчеркивания — таково стандартное 
соглашение глобальных имен в С. 
    Напишите функцию как любую другую отдельную ассемблерную процедуру, 
обычно, между директивами PROC и ENDP (строки 7-14). Вы сами ответственны за 
возврат всех необходимых значений в соответствующих регистрах, предохранение 
от порчи стека, сохранение и восстановление регистров bр и ds и прочую 
низкоуровневую работу. В данном случае функция возвращает длинные целые 
значения в паре регистров ax:dx (строки 11, 12). Не имеет смысла также 
сохранять и восстанавливать bр и стековый указатель sp, поскольку в функции не 
используются параметры, передающиеся через стек, или переменные в стеке. 
    Теперь вы владеете всеми необходимыми компонентами для ассемблирования и 
компиляции примера. С помощью TASM.EXE и автономного компилятора ВСС.ЕХЕ, 
доступных по установленным маршрутам, и находясь в каталоге, содержащем файлы 
TESTTIME.CPP, TIMER.Н и TIMER.ASM, введите из командной строки DOS команду bcc 
testtime timer.asm. Сначала компилятор C++ скомпилирует TESTTIME.CPP в 
TESTTIME.OBJ, затем TASM ассемблирует TIMER.ASM в TIMER.OBJ Наконец, 
компоновщик объединит объектные файлы в исполняемом файле TESTTIMER.EXE. 
Запустите программу и нажмите любую клавишу для остановки таймера. 


    450     Часть IV. Разработка приложений 
