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

    pop	bp                          ;  Восстановить сохраненные регистры 
    pop	di 
    pop	si 
    pop	ds 
    pop	es 
    pop	dx 
    pop	сx 
    pop	bx 
    pop	ax 
    iret	; Вернуться к выполнению прерванной программы 

    После восстановления регистровых значений, сохраненных ранее в стеке, 
функция выполняет инструкцию iret, которая возвращает управление либо 
прерванной программе, либо, в случае программного прерывания, в место 
выполнения инструкции int. При этом также восстанавливаются регистры и флаги, 
запомненные в стеке во время возникновения сигнала или инструкции прерывания. 
    В листинге 17.11 демонстрируется написание и установка функций — 
обработчиков прерываний, написанных с помощью встраиваемых инструкций asm. Вы 
должны скомпилировать и запустить эту программу из подсказки DOS. Программа 
устанавливает свой обработчик вектора прерывания PC 0x1c, который обычно не 
выполняет никаких действий, но тем не менее регулярно вызывается функцией 
BIOS, которую, в свою очередь, вызывает внутренний системный таймер. 
Вызываемый с частотой примерно 17.2 раза в секунду, вектор прерывания 0x1c 
играет роль удобного "крючка" с подвешенными действиями, которые необходимо 
выполнять регулярно, пока программа продолжается, даже не подозревая о 
прерываниях. В MULTIP прерывание запрограммировано отображать время в правом 
верхнем углу текстового дисплея, пока вы вводите тестовую строку. Нажмите 
<Enter> для завершения программы и удаления обработчика прерывания из памяти. 

   ЗАМЕЧАНИЕ

   Если у вас монохромный адаптер дисплея, замените 0xb800 в строке 5 на 0xb000.


    Листинг 17.11.  MULTIP.CPP (демонстрация процедуры обработки прерывания) 

    1:   #include <stdio.h> 
    2:   #include <dos.h> 
    3:   #include <string.h> 
    4: 
    5:  #define DISPSEG 0xb800 // 0хb000 для монохромного дисплея 
    6:	
    7: // Глобальная переменная для первоначального вектора прерывания 0x1с 
    8: void interrupt (far *oldVector){...}; 
    9: 
  10: // Прототипы функций 
  11: void Initlnterrupt(void); 
  12: void DoWhateverYouWant(void); 
  13: void Deinitlnterrupt(void); 
  14: void interrupt ShowTime(...); 
  15: 
  16: main() 
  17: { 
  18:  setcbrk(0); // Предотвращение завершения программы с <Ctrl+C> 
  19:  Initlnterrup();
  20:  DoWhateverYouWant(); 
  21:  Deinitlnterrupt(); 
  22:  return 0; 
  23: } 
  24: 
  25: // Перенаправляет вектор прерывания на нашу процедуру обработки 
  26: void Initlnterrupt(void) 
  27: { 
  28:  oldVector = getvect(0x1c); // Save current vector 
  29:  setvect(0x1c, ShowTime); // Set vector to ShowTime() 
  30: } 
    

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