Данному образовательному сайту пришлось несколько раз менять свое имя. С 2022 года доступ к нему обеспечивается по URL
emc.orgfree.com

emc.km.ru (2001-2007) ==> educomp.org.ru (2007-2011) ==> educomp.runnet.ru (2011-2021) ==> emc.orgfree.com (2022-...)
Более подробно об истории сайта можно прочитать здесь.


Учебные модели компьютера



Модели (software):

"Е14" (parallel !!!)
"S9PU" (parallel)

Модели (hardware):






Награды сайта
Награды сайта 2005
(Продолжение. Начало см. здесь.
Можно также загрузить исходные файлы проектов.)

Изучение средствами Delphi способов хранения в компьютерной памяти различных данных
1. Технология эксперимента

1.1. Оператор absolute

В основе всех наших экспериментов с памятью будет лежать оператор absolute. Изначально он предназначен для задания переменной абсолютного адреса, но в таком виде он нам бесполезен, поскольку одна из проблем как раз в том и заключается, что адрес переменной в ОЗУ неизвестен. Но у оператора есть еще частная форма, которая имеет синтаксис:

var a: <type1>;
    b: <type2> absolute a;

Описание означает, что адресом памяти для переменной b компилятор назначит тот же самый адрес, который имеет переменная a. Если переменные a и b к тому же имеют одинаковую длину в байтах (сама конструкция absolute этого, разумеется, не требует), то можно говорить о том, что они в памяти полностью совпадают и «наложены» друг на друга. Очень важно подчеркнуть, что типы переменных <type1> и <type2> совершенно произвольны, так что мы получаем поистине редкую возможность общаться с одной и той же областью памяти разными способами.

Конструкция absolute
Рис. 1. Принцип работы оператора absolute

На рис. 1 приведен конкретный пример такого совмещения переменных. Изучаемая переменная test хранится в памяти начиная с адреса N. Мы не можем его узнать, но с помощью конструкции absolute имеем возможность «наложить» на test массив b из четырех байт, что позволит нам получить доступ к любому из них через элементы массива b[1]-b[4]. А это-то нам как раз и нужно! Интересно, что аналог подобной конструкции существовал в Фортране ЕС ЭВМ и назывался COMMON – общая область памяти.

Желательно понимать, что применение оператора absolute для разных типов переменных потенциально опасно, поскольку, пользуясь операциями над <type1> можно получить результат, недопустимый для <type2>. Но мы будем все делать внимательно и аккуратно, так что новый оператор не принесет нам ничего, кроме пользы.

1.2. Консольное приложение

Для многих простых экспериментов не требуется организовывать удобный пользовательский интерфейс. Например, если нас интересует минимальное значение типа EXTENDED и программа его как-то вычисляет, то достаточно вывести результат на экран как в старых MS-DOS программах. Конечно, можно было бы создать на форме метку или поле редактирования и вывести туда результат, но это сильно напоминает то, что в народе называют «стрельбой из пушки по воробьям».

В свете сказанного, многие наши простые эксперименты будем выполнять в виде так называемых консольных приложений, которые хотя и до боли напоминают черное окно исполнения Турбо Паскаля, но, тем не менее, пишутся на принятом в Delphi диалекте

Паскаля и главное – в удобной оконной среде разработки. Чтобы создать консольное приложение, достаточно в меню File выбрать пункт New и далее, поскольку консольное приложение «не самый ходовой товар», пункт Other... (другие – см. рис. 2).

создание консольного приложения
Рис. 2. Создание консольного приложения (начало)

В открывшемся диалоговом окне среди многочисленных вариантов приложений остается только найти и выбрать Console Application (рис. 3).

создание консольного приложения
Рис. 3. Создание консольного приложения (выбор)

В итоге «волшебник» (wizard) создания приложений автоматически сгенерирует следующий небольшой фрагмент:

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils;

begin
  { TODO -oUser -cConsole Main : Insert code here }
end.

Описания переменных в нем рекомендуется располагать непосредственно перед словом begin, а саму программу – между комментарием “Insert code here”, т.е. «вставьте код (программу!) здесь» и словом end. Как это выглядит на практике, рассмотрим на конкретном примере.

1.3. Пример задачи: хранение в памяти многобайтовых данных

Пусть в процессоре лежит некоторое целое число, размер которого составляет несколько байт (для определенности возьмем 32-битное целое типа LONGINT, хотя конкретное количество бит и тип несущественны). Думаю, все понимают, что процессор хранит это число в одном из своих регистров как единое целое4. Возникает вопрос: как сохранить это единое 4-байтовое число в ОЗУ, каждая ячейка которого имеет емкость 1 байт?

Пусть (опять-таки для определенности) число равно 1234567816. Очевидно, что каждый байт числа – это две шестнадцатеричные цифры и разбиение на байты следующее: 12 34 56 78. Тогда возможно два одинаково логичных способа сохранения нашего числа в четыре последовательных байта ОЗУ. Они изображены на рис. 4.

big/little endian
Рис. 4. Хранение многобайтовых данных в ОЗУ
(A – big endian, B – little endian)

В варианте A байт с наиболее значащей частью («big-end», в исходном числе он находится слева) сохраняется в память по наименьшему адресу (на рисунке это N). Такой способ принято называть «big-endian». В варианте B этот байт, напротив, сохраняется в память по наибольшему адресу (на рисунке это N+3). Следовательно первым, наоборот, сохраняется байт с наименее значащей частью («little-end», в исходном числе находится справа). Это, как понятно по аналогии, «little-endian». По-русски обычно используют не очень удачные эквиваленты терминов: big-endian – это обратное размещение байтов, а little-endian – прямое. Хотя для математиков нумерация байтов «с младшего конца» более естественна, но язык не поворачивается, глядя на рис. 4, называть способ B прямым.

Кстати говоря, термины big-/little-endian были предложены в одной из статей, посвященных рассматриваемому вопросу, со ссылкой на книгу Джонатана Свифта «Приключения Гулливера». Как вы, наверно, помните, в Лилипутии ради обсуждения проблемы с какого конца – тупого или острого (по-английски «big side» или «little side») разбивать яйцо были созданы две непримиримые политические партии.

Из литературы известно, что в компьютерах IBM PC принят прямой (little-endian, вариант B на рис. 4). Это утверждение мы и хотим экспериментально проверить.

Эксперимент 1. Порядок байтов данных в памяти IBM PC

Постановка задачи. Имеется некоторая величина, состоящая из нескольких байт, например, целое число. Рассмотрим для конкретности 4-байтовый тип LONGINT, хотя все сделанные выводы распространяются и на другие числовые многобайтовые типы. Вопрос: как (в каком порядке) байты числа лежат в памяти ПК IBM PC?

Реализация эксперимента. Создадим консольное приложение, как описано выше, и дополним его небольшой программкой, в соответствии с листингом 1 (цветом выделен текст, который надо набрать в дополнение к автоматически сгенерированному Delphi).

Листинг 1
program byte_order;

{$APPTYPE CONSOLE}

uses
  SysUtils;
const Nb=4;
type  t=longint;
var   test: t;
      b: array [1..Nb] of byte absolute test;
      i: integer;
begin
  { TODO -oUser -cConsole Main : Insert code here }
  for i:=1 to Nb do b[i]:=0;
  b[Nb]:=1;
  writeln(test);
  for i:=1 to Nb do write(b[i]:4);

  readln;
end.

Верхний фрагмент описывает переменные test и b, которые «наложены» в памяти друг на друга в полном соответствии с рис.1. (Конечно, без обозначения констант и типов вполне можно было обойтись, но более общая форма записи облегчит, если потребуется, расширение программы.)

Обратимся теперь ко второй части, описывающей собственно эксперимент. Суть его сводится к тому, что в массиве (и одновременно в числе) создается последовательность байт 0 0 0 1, которая затем выводится на экран. Если бы IBM PC использовал big-endian представление чисел, на экране мы увидели бы единицу. На практике результат другой – см. рис. 5.

результат выполнения программы
Рис. 5. Результат работы листинга 1

Проверка на калькуляторе показывает, что число 16777216 есть 224, что прекрасно согласуется с переводом исходного числа 01 00 00 0016 в десятичную систему.

Зато если единицу положить не в последний, а в первый элемент массива (b[1]:=1), то в полном соответствии с теорией на экране появится единица.

Вывод. ПК IBM PC использует little-endian порядок байт. На практике это означает, что прочитанные из памяти байты для правильного формирования многобайтовых данных следует переставлять! (01 00 00 00 ==> 00 00 00 01 и т.п.)

Заметим, что данный вывод ни в коем случае не следует распространять на ASCII строки, поскольку там каждый символ рассматривается по отдельности (сравните 4-байтовое число и 200-символьную строку, которая даже не поместится единовременно ни в один из регистров процессора!)




4 битов в регистрах современного процессора хватит даже на 8-байтовое число!


© Е.А.Еремин, 2010
Публикация:
Еремин Е.А. Изучение средствами Delphi способов хранения в компьютерной памяти различных данных. Информатика, 2010, N 19, с.4-23.


Автор сайта - Евгений Александрович Еремин (Пермский государственный педагогический университет). e_eremin@yahoo.com


Free Web Hosting