В деяких випадках для роботі з пам’ятю функцій бібліотеки Turbo C не достатньо або їх використання не ефективно. В
такому випадку доводиться виконувати безпосередньо доступ до МСВ-блоків із СИ – програми. В п.6.1.1 розглянуто функції MS-DOS, які використовуються для динамічного управління пам’ятю. Звертаючись до таких функцій
безпосередньо з СИ – програми (за допомогою функції int86(),geninterrupt(),intdos() та ін.), можна створити або звільнити блок
пам’яті, а також змінити його розмір. Крім цього, Turbo C має функції-аналоги: allocmem(),freemem() и setblock(); далі наведена їх специфікація.
# include <dos.h>
int allocmem
(unsigned size, unsigned *segp)
Звертаючись до функцій AH=48h переривання 21h, запитуючи створення MS-DOS блока пам’яті
розміром size параграфів. В успішному
випадку повертається –1. Номер параграфа, з якого починається в пам’яті створений блок, розміщується в комірку пам’яті, на яку вказує segp. Блок буде розміщений в пам’яті на
границі параграфу, починаючи з фізичної адреси segp:0. За адресою segp-1:0000 буде
розміщуватись МСВ створеного блоку. Байти 1-2 цього МСВ (див.5.1) тримають PID (сегмент PSP)
поточної програми. В противному випадку функція повертає розмір в параграфах
найбільшого вільного MS-DOS блока пам’яті та записує в зовнішню змінну_errno код помилки ENOMEM.
По завершенню програми
створенні за допомогою allocmem() блоки пам’яті не звільняються MS-DOS і їх звільнення потребує
виклику функції freemem().
#
include <dos.h>
int freemem (unsigned segx)
Звертаючись до функцій AH=49h переривання 21h для звільнення МСВ-блока пам’яті, початковий параграф якого задає segx. У випадку вдачі повертається 0, в іншому випадку повертається –1 та в
зовнішню змінну errno встановлюється значення ENOMEM.
#
include <dos.h>
int setblock (unsigned segx,
unsigned newsize)
Звертаючись до функцій AH=4Ah переривання 21h, спробує встановити новий розмір в newsize параграфів для блока, початковий параграф якого
задає segx. В успішному випадку функція повертає –1. В противному
вона повертає розмір в параграфах найбільшого вільного МСВ-блоку
пам’яті та записує в зовнішню змінну _errno код помилки ENOMEM.
Наведемо приклад програми, яка використовує описані вище функції для
керування пам’ятю. Програма створює блок пам’яті куди розміщує копію екрана в
текстовому режимі (25x80, кольоровий). Після цього очищає екран
і після натискання будь-якої клавіші встановлює його в попереднє становище. Для
програм, що використовують функції MS-DOS керування пам’ятю, дуже
важливо “чисте” завершення з звільненням виділених блоків пам’яті, наприклад по
завершенні по Ctrl-Break. З цією метою в
наведеній програмі встановлюється власний об робітник виключної ситуації
(докладніше по завершенні по CTRL-Break див. В 5.6). Для очистки екрана
використовується макро, яке виконує скролінг.
/*L6_6.c*/
#include <stdio.h>
#include <signal.h>
#include <process.h>
#include <dos.h>
#include <mem.h>
unsigned seg; /*сегмент початку МСВ-блока
пам’яті;
описується як зовнішня змінна для бачення в ctrl_c_handler()*/
/*”Заливка” екрана в текстовому режимі
кольором color.*/
#define FILLSCREAN(color)
_AX=0x0000; _DX=0x184f;\
_BH=color,geninterrupt(0x10);
/*Внутрішня функція програми L6_6.c. Звільняє
МСВ-блок пам’яті при натисканні Ctrl-C (Ctrl-Break).*/
void ctrl_c_handler(int sig)
{signal(SIGINT,SIG_IGN);
/*Блокує повторне входження*/
/*Встановлення екрана та звільнення виділеного
блоку */
movedata(seg,0,0xb800,0,4000);
freemem(seg);
puts(“\a Звільнений виділений блок пам’яті”);
exit(5);
}
int main(void)
{register unsigned
ret; int ch;
/*Спроба пере розділити МСВ-блока пам’яті розміром 4000 байт. */
if((ret=allocmem(4000>>4,&seg))!=-1)
{
print(“Вільно лише %u параграфів пам’ті. Завершення.”,ret);
return 1;
}
/* Встановлення власної реакції на Ctrl-C (Ctrl-Break).*/
if(signal(SIGINT,ctrl_c_handler)=SIG_ERR)
{perror(“Помилка встановлення об
робітника SIGINT”);return 3;}
/*Переміщення змісту відео буфера в виділений блок пам’яті*/
movedata(0xb800,0,seg,0,4000);
FILLSCREAN(0x1f);
Puts(“Завершення? (Y/N)”);
While(!((ch=getchar()==’Y’ || ch==’y’));
/*Встановлення екрана та звільнення виділеного
блока. */
movedata(seg,0,0xb800,0,4000);
freemem(seg);
return 0;
}
![]() |
![]() |
![]() |