МАРК РЕГНЕРУС ДОСЛІДЖЕННЯ: Наскільки відрізняються діти, які виросли в одностатевих союзах
РЕЗОЛЮЦІЯ: Громадського обговорення навчальної програми статевого виховання ЧОМУ ФОНД ОЛЕНИ ПІНЧУК І МОЗ УКРАЇНИ ПРОПАГУЮТЬ "СЕКСУАЛЬНІ УРОКИ" ЕКЗИСТЕНЦІЙНО-ПСИХОЛОГІЧНІ ОСНОВИ ПОРУШЕННЯ СТАТЕВОЇ ІДЕНТИЧНОСТІ ПІДЛІТКІВ Батьківський, громадянський рух в Україні закликає МОН зупинити тотальну сексуалізацію дітей і підлітків Відкрите звернення Міністру освіти й науки України - Гриневич Лілії Михайлівні Представництво українського жіноцтва в ООН: низький рівень культури спілкування в соціальних мережах Гендерна антидискримінаційна експертиза може зробити нас моральними рабами ЛІВИЙ МАРКСИЗМ У НОВИХ ПІДРУЧНИКАХ ДЛЯ ШКОЛЯРІВ ВІДКРИТА ЗАЯВА на підтримку позиції Ганни Турчинової та права кожної людини на свободу думки, світогляду та вираження поглядів
Контакти
Тлумачний словник Авто Автоматизація Архітектура Астрономія Аудит Біологія Будівництво Бухгалтерія Винахідництво Виробництво Військова справа Генетика Географія Геологія Господарство Держава Дім Екологія Економетрика Економіка Електроніка Журналістика та ЗМІ Зв'язок Іноземні мови Інформатика Історія Комп'ютери Креслення Кулінарія Культура Лексикологія Література Логіка Маркетинг Математика Машинобудування Медицина Менеджмент Метали і Зварювання Механіка Мистецтво Музика Населення Освіта Охорона безпеки життя Охорона Праці Педагогіка Політика Право Програмування Промисловість Психологія Радіо Регилия Соціологія Спорт Стандартизація Технології Торгівля Туризм Фізика Фізіологія Філософія Фінанси Хімія Юриспунденкция |
|
|||||||||||||||||||||||||||||||
Короткі та довгі вказівники. Модифікатори вказівників
Молодші моделі пам'яті використовують один спільний сегмент для всіх даних програми. Вони передбачають, що сегментна частина адрес усіх даних зберігається в системному регістрі 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; } Читайте також:
|
||||||||||||||||||||||||||||||||
|