В деяких випадках для роботі з памятю функцій бібліотеки 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;

}