Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
8
Добавлен:
12.02.2016
Размер:
552.98 Кб
Скачать

Старші моделі: Compact, Large і Huge використовують окремий сегмент для стеку тa лише зовнішню динамічну пам'ять.

Для великих багатофайлових програм доцільно застосовувати розподіл пам'яті за моделлю Large, яка зберігає код кожного програмного файла в окремому сегменті (рис. 2).

Якщо ж обсяг статичних даних програми перевищує 64 Кбайт, то слід встановити модель Huge.

11/37

3. Короткі та довгі вказівники. Модифікатори вказівників

Молодші моделі пам'яті використовують один спільний сегмент для всіх даних програми. Вони передбачають, що сегментна частина адрес усіх даних зберігається в системному регістрі DS.

Тому для адресації змінних достатньо задавати тільки два байтові значення зміщень. Відповідні вказівники, які зберігають зміщення фізичних адрес, називають короткими (чи ближніми) або near-вказівниками.

За замовчуванням двобайтовий формат встановлено для всіх вказівників у молодших моделях пам'яті (див. табл. 1).

12/37

 

 

(поточна межа ДП)

 

 

Зовнішня ДП

SS:FFFF

 

Динамічні дані

 

 

 

 

 

 

 

 

 

 

 

SS:SP

 

Локальні дані (стек)

 

Сегмент стека

 

 

 

 

 

 

 

(поточна межа стека)

 

(<64К)

SS:0000

 

Сегмент даних

 

 

 

DS:0000

 

Глобальні і статичні дані

 

(<64К)

 

 

 

 

 

 

 

 

 

 

CS(k):0000

 

Код програмного файла k

 

<64К Сегменти

 

 

 

 

 

<64К програмних

 

 

 

 

 

 

 

 

 

< 64 К кодів

 

 

Код програмного файла 1

 

 

 

 

 

 

 

 

CS(1):0000

Рис. 2. Схема розподілу оперативної пам'яті в моделі Large

13/37

У старших моделях пам'яті для даних і коду програми виділяється декілька сегментів оперативної пам'яті та використовується зовнішня динамічна пам'ять. Тому в цих моделях адреса зберігається в чотирибайтовому форматі: два старші байти задають сегмент, а два молодші - зміщення адреси.

Вказівники старших моделей називають довгими (чи дальніми) або far- вказівниками. Коли відбувається звертання до об'єкта через far-вказівник, сегмент адреси записується у відповідний сегментний регістр для формування фізичної адреси цього об'єкта.

Довгі вказівники дають змогу звернутись до кожного байта оперативної пам'яті в межах перших 1 Мбайт.

Формат вказівника, встановлений автоматично за заданою моделлю пам'яті, можна змінити, використовуючи модифікатори near, far або huge (всі три є зарезервованими словами Borland C). Модифікатор формату записують після базового типу вказівника перед символом *, наприклад:

char far* psymb;

14/37

near-, farта huge-вказівники.

Вказівники з модифікатором near є 16-розрядними беззнаковими цілими числами, що зберігають тільки зміщення адреси, їх доцільно застосовувати в програмах, сумарний обсяг даних яких не перевищує обсягу сегмента (64 Кбайт).

Застосування коротких вказівників у багатосегментних програмах вимагає перевизначення сегментного регістра DS або використання спеціальних форм near-вказівників, про які мова йтиме далі.

Вказівники з модифікатором far 32-розрядні, вони зберігають повну адресу об'єкта, тобто сегмент і зміщення. Такі вказівники застосовують у молодших моделях пам'яті, коли потрібно звернутись до об'єктів, розташованих за межами сегмента коду програми чи сегмента даних. Зокрема, far-вказівники використовують для роботи з даними у зовнішній динамічній пам'яті, для безпосереднього звертання до відеопам'яті, для доступу до адресного простору

BIOS тощо.

Наведемо приклад функції, яка дає змогу записати заданий символ в останню позицію екрана (правий нижній кут). Нагадаємо, що в разі заповнення цієї позиції будь-якою стандартною функцією виведення даних, відбувається автоматичний скролінг екранного зображення - зсув усіх рядків на один угору. Тому функція заповнення останнього знакомісця має важливе практичне значення.

15/37

/* Функція виведення символа в позиції екрана (80,25) */ void PutLastScrSmb (char symb, char attr)

{

/* symb - код символа; attr - атрибути: колір символа і колір фону */ char far* VMadr = (char far *)0xb8000000; /* початок відеопам'яті */

VMadr += (24*80+79)*2;

/* адреса останнього символа екрана */

*VMadr = symb;

/* відображення символа */

if (attr)

/* якщо треба змінити кольори */

*(VMadr+l) =attr; }

 

У разі роботи з довгими вказівниками часто виникає потреба поділу значення адреси на складові частини: сегмент і зміщення, чи, навпаки, необхідність формування довгого вказівника зі складових частин. Для виконання цих операцій призначені спеціальні макроси, оголошені в заголовному файлі

<dos .h>:

unsigned FP_SEG (void far* ptr); unsigned FP_OFF (void far* ptr);

void far* MK_FP (unsigned seg, unsigned off);

16/37

Два перших макроси FP_SEG () і FP_OFF () виділяють з адреси, занесеної у far-вказівник ptr, відповідно сегментну частину та зміщення. Макрос MK_FP () формує значення довгого вказівника зі заданого сегмента seg і зміщення off. За допомогою цього макроса адресу останнього символу екранного зображення, яка використовувалася у функції PutLastScrSmb (), можна сформувати, наприклад, так:

char far* VMadr= (char far*)MK_FP(Oxb800, 25*80*2-2);

Якщо тепер оголосити:

 

unsigned of s = FP_OFF( VMadr);

/* виділення зміщення */

то змінна ofs отримає значення 3998, що відповідає зміщенню в байтах (відносно початку відеопам'яті) знакомісця екрана з координатами (80, 25).

Іншим способом формування довгих адрес та виділення їх складових частин є використання структур і об'єднань. Такий підхід дає змогу одночасно виконувати перетворення базового типу вказівника, тобто змінювати форму доступу до даних.

17/37

Розглянемо два наступних оголошення:

struct mem_addr {

 

 

unsigned ofs, segm;

/* зміщення та сегмент фізичної адреси */

};

 

 

union addr_convert {

 

 

struct mem_addr adr;

 

 

char far *pb;

/* вказівники

*/

unsigned far *pw;

/* на дані

*/

unsigned long far *pl; }

/* різних типів

*/

uptc;

 

 

}

 

 

Змінна uptc має тип об'єднання union addr_convert, до складу якого входять структура adr і три вказівники з різними базовими типами: pb, pw і рl. Поля ofs і segm структури adr задають зміщення і сегмент потрібної фізичної адреси.

Оскільки в far-вказівниках сегментна компонента займає два старші байти, а зміщення-два молодші, то поля структури adr треба записувати у відповідному порядку: спочатку зміщення, а потім сегмент адреси.

Зміна значень полів структури adr викликає відповідну зміну значення кожного з вказівників, оголошених у полях об'єднання uptc.

18/37

Наприклад, наступні присвоєння:

uptc.adr.segm = 0x0;

/* сегмент адреси */

uptc.adr.ofs = 0x0450;

/* зміщення адреси */

сформують адресу 0000:0450h, починаючи з якої в оперативній пам'яті зберігається інформація BIOS про поточні координати текстового курсора для кожної з восьми сторінок відеопам'яті. Тепер до цих BIOS-даних можна звертатись побайтово, використовуючи вказівник pb, двобайтовими словами через вказівник pw або чотирибайтовими словами через вказівник рl. Зокрема, поточну позицію курсора на нульовій (основній) відеосторінці можна отримати так:

cur_x = *uptc.pb;

/* горизонтальна координата */

cur_y = * (uptc.pb+1);

/* вертикальна координата */

або можна зчитати відразу обидві координати:

cur_pos = *uptc.pw;

/* читання двобайтового слова */

Використання far-вказівників пов'язане з певними проблемами, про які необхідно пам'ятати, розробляючи програми з цими вказівниками.

19/37

По-перше, одну і ту ж фізичну адресу можна задати різними значеннями вказівника. Обидва оголошені вказівники:

unsigned far* adr1= (unsigned far*)0x00000410; unsigned far* adr2= (unsigned far*)0x00410000;

задають спільну адресу початку області даних відеопараметрів BIOS. Проте в разі порівняння цих вказівників: adr1==adr2 - результат буде хибним, бо порівнюються числові значення, записані в adr1 та adr2. А в разі порівняння far- вказівників операціями <, <=, >, >= перевіряються тільки зміщення, тобто молодші половини адрес.

Другою проблемою є міжсегментний перехід. Якщо до адреси far- вказівника додати певне число, то змінюється тільки зміщення адреси, а перенесення в сегментну половину не відбувається.

Вказаних недоліків не мають вказівники з модифікатором huge. В операціях з цими вказівниками беруть участь усі 32 розряди їхніх значень.

Після кожної операції виконується нормалізація вказівника: значення сегмента коректується так, щоб значення зміщення не перевищувало 15.

20/37

Соседние файлы в папке ТА_Методички