МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах
РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ" ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах Гендерна антидискримінаційна експертиза може зробити нас моральними рабами ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів Контакти
Тлумачний словник |
|
|||||||||||||||||||||||||||||||
Короткі та довгі вказівники. Модифікатори вказівників
Молодші моделі пам'яті використовують один спільний сегмент для всіх даних програми. Вони передбачають, що сегментна частина адрес усіх даних зберігається в системному регістрі DS.
Тому для адресації змінних достатньо задавати тільки два байтові значення зміщень. Відповідні вказівники, які зберігають зміщення фізичних адрес, називають короткими (чи ближніми)або near-вказівниками.
За замовчуванням двобайтовий формат встановлено для всіх вказівників у молодших моделях пам'яті (див. табл. 1).
Рис. 2. Схема розподілу оперативної пам'яті в моделі Large
У старших моделях пам'яті для даних і коду програми виділяється декілька сегментів оперативної пам'яті та використовується зовнішня динамічна пам'ять. Тому в цих моделях адреса зберігається в чотирибайтовому форматі: два старші байти задають сегмент, а два молодші - зміщення адреси.
Вказівники старших моделей називають довгими (чи дальніми)або far-вказівниками. Коли відбувається звертання до об'єкта через far-вказівник, сегмент адреси записується у відповідний сегментний регістр для формування фізичної адреси цього об'єкта.
Довгі вказівники дають змогу звернутись до кожного байта оперативної пам'яті в межах перших 1 Мбайт.
Формат вказівника, встановлений автоматично за заданою моделлю пам'яті, можна змінити, використовуючи модифікатори near, far або huge (всі три є зарезервованими словами Borland C). Модифікатор формату записують після базового типу вказівника перед символом *, наприклад: char far* psymb; near-, far- та huge-вказівники. Вказівники з модифікатором near є 16-розрядними беззнаковими цілими числами, що зберігають тільки зміщення адреси, їх доцільно застосовувати в програмах, сумарний обсяг даних яких не перевищує обсягу сегмента (64 Кбайт). Застосування коротких вказівників у багатосегментних програмах вимагає перевизначення сегментного регістра DS або використання спеціальних форм near-вказівників, про які мова йтиме далі. Вказівники з модифікатором far 32-розрядні, вони зберігають повну адресуоб'єкта, тобто сегмент і зміщення. Такі вказівники застосовують у молодших моделях пам'яті, коли потрібно звернутись до об'єктів, розташованих за межами сегмента коду програми чи сегмента даних. Зокрема, far-вказівники використовують для роботи з даними у зовнішній динамічній пам'яті, для безпосереднього звертання до відеопам'яті, для доступу до адресного простору BIOS тощо. Наведемо приклад функції, яка дає змогу записати заданий символ в останню позицію екрана (правий нижній кут). Нагадаємо, що в разі заповнення цієї позиції будь-якою стандартною функцією виведення даних, відбувається автоматичний скролінгекранного зображення - зсув усіх рядків на один угору. Тому функція заповнення останнього знакомісця має важливе практичне значення. /* Функція виведення символа в позиції екрана (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);
Два перших макроси 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).
Іншим способом формування довгих адрес та виділення їх складових частин є використання структур і об'єднань. Такий підхід дає змогу одночасно виконувати перетворення базового типу вказівника, тобто змінювати форму доступу до даних. Розглянемо два наступних оголошення:
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. Наприклад, наступні присвоєння:
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-вказівників пов'язане з певними проблемами, про які необхідно пам'ятати, розробляючи програми з цими вказівниками. По-перше, одну і ту ж фізичну адресу можна задати різними значеннями вказівника. Обидва оголошені вказівники:
unsigned far* adr1= (unsigned far*)0x00000410; unsigned far* adr2= (unsigned far*)0x00410000;
задають спільну адресу початку області даних відеопараметрів BIOS. Проте в разі порівняння цих вказівників: adr1==adr2 - результат буде хибним, бо порівнюються числові значення, записані в adr1 та adr2. А в разі порівняння far-вказівників операціями <, <=, >, >= перевіряються тільки зміщення, тобто молодші половини адрес.
Другою проблемою є міжсегментний перехід. Якщо до адреси far-вказівника додати певне число, то змінюється тільки зміщення адреси, а перенесення в сегментну половину не відбувається.
Вказаних недоліків не мають вказівники з модифікатором huge. В операціях з цими вказівниками беруть участь усі 32 розряди їхніх значень.
Після кожної операції виконується нормалізація вказівника: значення сегмента коректується так, щоб значення зміщення не перевищувало 15. Наприклад, адреса 8C65:12A4h у нормалізованій формі записується так: 8D8F:0004h. Нормалізація забезпечує однозначність запису кожної фізичної адреси й коректність усіх операцій порівняння та адресної арифметики, в тому числі пов'язаних із міжсегментними переходами. Тому для безпомилкової роботи з блоками даних, обсяги яких перевищують обсяг сегмента, треба використовувати huge-вказівники, хоча при цьому дещо збільшується час виконання програми через додаткові операції нормалізації.
Наступна функція застосовує huge-вказівник для визначення суми всіх машиних слів адресного простору BIOS, починаючи з адреси F000:0000h до FFFF:000Fh включно; сума є унікальною для кожної серії персональних комп'ютерів і може бути використана в програмах захисту інформації.
/* Функція обчислення суми слів BIOS-області. Варіант 1 */ unsigned long Summa_BIOS (void) { unsigned long sum=0; unsigned huge* ph =(unsigned huge*)0xf0000000; /* початок області */ while (ph) /* остання адреса - ffff:000fh */ sum += *ph++; return sum; } Читайте також:
|
||||||||||||||||||||||||||||||||
|