MS-DOS и TASM 2.0. Часть 18. Ещё раз об указателе.

Указатель в программировании.

Указатель в программировании.

В статье MS-DOS и TASM 2.0. Часть 9. Указатель просто и понятно было рассмотрено, что такое указатель в программировании (pointer). Сейчас мы перейдём к вопросу практического использования указателя. Ещё раз напомним, что указатель в ассемблере — более широкое понятие, чем в Си и С++, где указатель определён как переменная, значением которой является адрес ячейки памяти. Указатель — не только переменная. Указатель в программировании на ассемблере — адрес определённой ячейки памяти. Жёсткой привязки к понятию «переменной» нет.

Преимущество указателя — простая возможность обращаться к определённой части исполняемого кода либо данных, избегая их дублирования. Например, один раз написав код функции, мы можем обращаться к нему неоднократно, осуществляя вызов указанной функции. Кстати, вызов функции — это переход исполнения кода по указателю, который для удобства «обозвали» понятным для человека названием (ну, например, «MyBestFunc»).

Указатель в программировании используется также для получения и передачи входных-выходных значений функций. С этим применением мы встретимся при Windows программировании.

Указатель — адрес ячейки памяти.

Указатель в программировании на ассемблере — адрес ячейки памяти, содержащей определённые последовательности цифр — блоки кода и данных. Блоки кода и данных называются значениями указателя, например: строка, массив, структура, функция, переменная, константа.

Указатель в программировании
Указатель — адрес ячейки памяти, содержащей блоки кода и данных.

Указателю можно присвоить условное обозначение (const_a, const_b, my_mass_1, MY_STRUCT_1, BitMask, my_prnt_func), определив тип данных или кода, на которые он указывает (db, dd, STRUC, RECORD, proc). Практически мы уже проделывали эти операции, создавая исходники наших простейших программ:

Работа с указателями.

Основная проблема начинающего программиста — это различие между указателем и значением, расположенным по адресу памяти, на которую указывает  указатель.

Получение значения, на которое указывает указатель в Си и C++ называется «разыменование указателя». Это понятие можно употреблять и в ассемблере.

Получать адрес ячейки памяти (значение указателя) при программировании на ассемблере можно двумя способами, назовём их «статический» и «динамический». Реализовано это с помощью инструкций OFFSET и LEA.

При «статическом» способе указатель будет вычислен во время компиляции. Он не меняется и не вычисляется в процессе выполнения программы. В очень упрощённой форме: его значение равно смещению в байтах от начала программы, спроецированной в память, плюс адрес в оперативной памяти — «точка входа», адрес загрузки программы в память, который задаётся во время компиляции и записывается в заголовке (в начале) файла. Таким образом полученное значение фактически является константой.

OFFSET (Offset — смещение).

Получить «статическим способом» указатель в программировании на ассемблере можно с помощью оператора OFFSET (оператор — команда компилятору — подпрограмме, которая собирает исполняемый файл из исходного кода, написанного языком программирование). Offset возвращает значение метки в памяти. Меткой является любое именованное значение кода и данных. Например, имя переменной, константы или массива (именованное обозначение блока данных). Имя функции — фактически также является меткой (именованным обозначением блока кода).

LEA (Load Effective Address — загрузить эффективный адрес).

При «динамическом» способе адрес вычисляется в процессе исполнения программы. Для этого используется команда LEA (Load Effective Address).

lea операнд1, операнд2

Операнд 1 — это регистр-приёмник (ax, bx, dx и т.д.), куда будет перемещён эффективный адрес (указатель) ячейки памяти, в которой расположен операнд2.

Для начала, необходимо усвоить, что результат оба способа дают одинаковый, но иногда компилятор не имеет возможности определить указатель во время сборки программы. Например, при выделении динамической памяти (столкнёмся в 32 битном Windows программировании), не известно, по какому адресу она будет выделена. Если по этому адресу у нас будет находиться структура, то определить указатель на поля структуры возможно с использованием команды LEA.

Указатель в программировании на примере ассемблерного кода.

Ниже мы приводим код, который необходимо внимательно изучить. Даётся подробный комментарий. Не поленитесь и прогоните исполняемый файл GBLPTR.COM через отладчик Turbo Debuger — только так можно изучить указатель в программировании и познать Дао…

Сегментная адресация.

Вы уже заметили, что указатель на код и данные состоит из двух частей: пары сегмента и смещения, разделённых двоеточием. Это связано с так называемой сегментной адресацией, используемой микропроцессора 8088, на базе которого работают современные Intel и  AMD процессоры. В этом микропроцессоре используется сегментная организация памяти.

Указатель в программировании - пример кода.
Фрагмент нашей программы, пропущенной через отладчик.

Имеется четыре сегментных регистра, к которым микропроцессор имеет одновременный доступ. Базовые адреса сегментов находятся в сегментных регистрах:

  • CS Регистр сегмента кода
  • DS Регистр сегмента данных
  • SS Регистр сегмента стека
  • ES Регистр дополнительного сегмента

Для доступа к данным внутри сегмента обращение производится относительно начала сегмента линейно, т.е. начиная с 0 и заканчивая адресом, равным размеру сегмента. Для обращения к любому адресу в программе, компьютер складывает адрес в регистре сегмента и смещение. Например, первый байт в сегменте кодов имеет смещение 0, второй байт – 1 и так далее.

Физический адрес, то есть непосредственный указатель на область памяти, принято записывать парой этих значений, разделенных двоеточием СЕГМЕНТ:СМЕЩЕНИЕ, например:
сs:014А
сs:0151
сs:0153

Как неоднократно говорилось, программа типа *.COM представляет собой практически живой образ данных и машинных команд, предназначенных для выполнения процессором. Отображается в оперативную память без изменений. Начальный адрес загрузки в память — 0100h. Все сегменты имеют одно значение — работают с одним блоком памяти (в нашем примере он находится по адресу 4CEAh).

Указатель в программировании — одно из основополагающих понятий, уяснение которого является обязательным для написания кода с применением любого языка. К программированию в системе Windows переходите, только основательно проштудировав данный вопрос.

Добавить комментарий