Chapter_09 (1110561), страница 6
Текст из файла (страница 6)
Например, даты, записанные как 01/01/110 и01/01/10 будет соответствовать одной "настоящей" дате 01/01/2010. Это происходит из-за того, что извсего возможного диапазона хранимых в таком виде 128 лет (0–127) мы использовали только диапазон в 100лет.2Как исключение метки, указанные как операнды в командах относительного перехода, как мы ужезнаем, имеют значения констант, задающих знаковое расстояние до точки перехода в байтах.18имён целочисленных констант, определяемых директивами эквивалентности – сами эти константы,значениями имён сегментов являются адреса начал этих сегментов в оперативной памяти, делённыена 16 и т.д.
Отметим, что некоторое имена могут вообще не иметь числовых значений, например,это, например, вот такое имя S, заданное директивойS equ [bp+6]Имя упакованного битового поля тоже имеет значение – это количество разрядов, на которое надо сдвинуть это поле, чтобы оно попало в самую правую позицию той области памяти (байта илислова) в которой хранится данное поле. Например, имя month имеет значение 7. Таким образом,имена упакованных битовых полей в Ассемблере предназначены в программе для задания числасдвигов слова или байта, что мы и использовали в нашем примере.Другое языковое средство, предоставляемое Ассемблером для работы с упакованными битовыми полями – это одноместный оператор, который задаётся служебным именем mask. Операндомэтого оператора должно являться имя упакованного битового поля, а значением данного операторабудет байт или слово, содержащее биты '1' только в позициях, занимаемых указанным полем, в остальных позициях будут находиться нулевые биты.
Как видим, оператор mask удобно использоватьдля задания констант (масок) в командах логического умножения для выделения нужного битовогополя, это и было продемонстрировано в нашем примере.И, наконец, рассмотрим ещё один оператор Ассемблера, предназначенный для работы с именами упакованных битовых полей. Значением оператораwidth <имя битового поля>является ширина этого поля, т.е. количество составляющих его бит. Например, для нашего описаниятипа date выражение width month равно 4.
Заметим, что если применить этот оператор к именитипа, задающего упакованные битовые поля, то значением оператора width будет сумма длин всехполей в этом типе. Например, width date равно 16. Оператор width достаточно редко встречается в практике программирования, и мы не будем приводить примеры его использования.Итак, из рассмотренного выше примера видно, что упакованные битовые поля, как и другие упакованные структуры данных, которые мы рассматривали ранее, позволяют экономить место в памяти для размещения данных, но требуют значительно больше команд для манипулирования такимиупакованными данными.
На этом закончим наше краткое знакомство с упакованными битовыми полями в языке Ассемблера.9.5. Структуры на АссемблереДругим примером описания типов в языке Ассемблера являются структуры. В языке Паскальаналогом структур Ассемблера являются записи, которые позволяют описать совокупность именованных переменных (вообще говоря, разных типов) как новый самостоятельный тип данных. Описания типа структуры задаются в языке Ассемблера в виде<имя типа структуры> strucПредложения резервированияпамяти под поля структуры<имя типа структуры> endsВ качестве примера рассмотрим описание простой структуры, предназначенной для храненияинформации о студенте: текстовой строки, в которой будет храниться фамилия студента (не более 20символов), а также трёх полей для хранения даты рождения (дня, месяца и года).Stud strucFiodb"********************"; 20 '*'db'$'Daydb?Month db?Year dw1986Stud endsВ нашей структуре описано 5 полей. Первое поле с именем Fio длиной 20 байт предназначенодля хранения фамилии студента, у этого поля есть значение по умолчанию – это строка из 20 символов '*'.
Обратите внимание на следующую тонкость: это предложение нельзя записать в виде19Fio db20 dup ('*'); 20 '*'так как в этом случае будет определено 20 полей длиной по одному байту каждое. Соответственно,если в первом случае имя Fio является именем всей строки символов (массива коротких целыхчисел), то во втором – будет только именем первого символа в массиве из 20 символов.Второе поле нашей структуры длиной в один байт не имеет имени, но имеет значение по умолчанию '$'.
Как видим, мы подготавливаем удобный способ вывода фамилии студента с использованием уже знакомой нам макрокоманды outstr. Три последних поля нашей структуры определяют переменные для хранения числовых значений дня, месяца и года рождения студента, причём угода рождения мы предусмотрели значение по умолчанию 1986.Каждое имя поля имеет целочисленное значение, которое равно смещению в байтах начала этогополя от начала структуры. Так, например, имя поля Month в описанной выше структуре Stud имеетзначение 22.После описания структуры можно резервировать в некотором сегменте переменные описанноготипа с помощью предложений резервирования памяти, например:St1StudSt2StudGrup Stud<'Иванов И.И.',,21,4><'Петров П.П.',,31,5,1985>30 dup (<>); Студенческая группаСтроки, задающие начальные значения фамилий, дополняются пробелами справа, если их длина менее длины поля (в нашем примере менее 20 символов).
Обратите внимание, что мы выделилидвумя запятыми подряд второе безымянное поля, которому при размещении переменной в памяти,таким образом, не присваивается нового значения, и это поле сохраняет начальное значение поумолчанию '$', определённое при описании структуры Stud. Для студента с фамилией Ивановмы не задали начального значения поля, в котором хранится год рождения, таким образом, это полебудет иметь начальное значение 1986, заданное в описании типа Stud.К сожалению, поля структуры могут принадлежать только к стандартным типам Ассемблера(db, dw, dd и т.д.).
Нельзя, например, задавать в виде полей структуры определённые пользователемупакованные битовые поля и другие структуры.В качестве небольшого примера рассмотрим фрагмент программы на Ассемблере, в котором выводится информация о студенте, хранящаяся в переменной с именем Z типа Stud.movdx,offset Z.Fiooutstrnewlinexorax,axmoval,Z.Dayoutword axoutch '/'moval,Z.Monthoutword axoutch '/'outword Z.YearnewlineВ этом примере мы встретились с новым двуместным оператором языка Ассемблер, которыйобозначается символом '.'. Этот оператор выполняется Ассемблером так же, как и двуместныйоператор '+', однако тип (размер) этого операнда задаётся тем именем, которое располагается послеточки. Таким образом, командаoutword Z.Yearэквивалента командеoutword word ptr Z+YearЭто показывает, как различаются правила вычисления типа выражения, в которое входит полеструктуры.
Так, хорошо изучив рекомендованный Вам учебник по языку Ассемблера, постарайтесьпонять, что type Z.Year=2 , type (Z+Year)=35 , а type Z+Year=68 . Другим отличием(для нашего примера, впрочем, несущественным), является различный приоритет операций Ас-20семблере '.' и '+'. Операция '.' имеет более высокий приоритет, чем операция '+', что можетоказаться полезным для записи некоторых выражений без использования круглых скобок. Приоритеты всех операций языка Ассемблер и правила вычисления типов Вам необходимо обязательно выучить по учебнику [5].В качестве ещё одного примера напишем на Ассемблере функцию со стандартным соглашениемо связях, которая получает в качестве параметров массив KURS структур с данными о студентах,длину этого массива N и беззнаковое целочисленное значение Y.
Функция будет вырабатывать в качестве своего значения количество студентов, родившихся в году Y. Соответствующие данные в Ассемблере можно, например, описать так (предполагаем, что структура Stud уже описана):NequKURS StudYdw500N dup (<>)?Тогда вызов нашей процедуры (дадим ей, не долго думая, имя P) будет производиться, например, командами:movpushmovpushpushcallax,offset KURSaxax,NaxYPНиже приведён возможный текст этой процедурыPprocpushmovpushpushpushmovmovmovxorjcxzL:cmpjneincL1:addloopVozv: poppoppoppopretPendpnearbpbp,spbxdxcxdx,[bp+4]; Год Ycx,[bp+6]; Длина массива Nbx,[bp+8]; Начало массиваax,ax; Число студентов с годом рождения YVozv; Всех студентов уже отчислили? ☺[bx].Year,dxL1axbx,type Stud; На след.
студента в массиве XLcxdxbxbp6Из этого примера видно, что значением одноместного оператора type, применённого к именитипа структуры (как, впрочем, и к имени самой переменной этого типа) является длина структуры вбайтах. Для нашего примера type Stud = type KURS = type St1 = 25. Здесь следует подчеркнуть, что наша функция, конечно, не знает, что переданный ей массив программист назвал именем KURS. В то же время для правильной работы функция обязана знать имя типа Stud, которыйимеют элементы массива, а также должна знать имена всех полей структуры, с которыми она работает. Стоит отметить, что это же будет справедливо и для аналогичной функции, написанной на Паскале.На этом мы завершим знакомство с дополнительными возможностями языка Ассемблер, болееподробно эту тему необходимо изучить по учебнику [5].21Вопросы и упражнения1.2.3.4.5.6.7.8.9.Что такое флаг направления?Напишите фрагмент программы на Ассемблере, который выводит на печать (по макрокомандеoutword) текущее значение флага направления (знать номер этого флага в регистре флаговдля этого не нужно).Почему необходимо уметь копировать массивы как в прямом, так и в обратном направлении?Определите, какие значения должен иметь флаг направления DF при операции вставки и приоперации удаления участка редактируемого текста в некотором текстовом редакторе, которыйиспользует для этих целей строковые команды.Что является операндами логических команд?Когда можно, а когда нельзя использовать команды сдвига для умножения и деления целыхчисел на степень двойки?В каком случае следует использовать в программе упакованные структуры данных?Как выполняется операция языка Ассемблера "точка".Для описания упакованного массива данныхNData; varAXequ10000segmentA: packed array[1..N] of 0..15;dbN/2 dup (?); N/2 ≡ N div 2db?Реализуйте оператор присваивания A[i]:=X..