Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Языки программирования. Практический сравнитель...doc
Скачиваний:
33
Добавлен:
09.09.2019
Размер:
2.68 Mб
Скачать

1.6. Стандартизация

Следует подчеркнуть значение стандартизации. Если для языка существует стандарт, и если компиляторы его поддерживают, то программы можно пере­носить с одного компьютера на другой. Когда вы пишете пакет программ, ко­торый должен выполняться на разных компьютерах, вы должны строго при­держиваться стандарта. Иначе задача сопровождения чрезвычайно усложнит­ся, потому что придется следить за десятками или сотнями машинно-зависи­мых вопросов.

Стандарты существуют (или находятся в стадии подготовки) для большин­ства языков, обсуждаемых в этой книге. К сожалению, обычно стандарт пред­лагается спустя годы после широкого распространения языка и должен сохра­нять машинно-зависимые странности ранних реализаций. Язык Ada — иск­лючение в том смысле, что стандарты (1983 и 1995) создавались и оценивались одновременно с проектом языка и первоначальной реализацией. Более того, стандарт ориентирован на то, чтобы компиляторы можно было сравнивать по производительности и стоимости, а не только на соответствие стандарту. Компиляторы зачастую могут предупреждать вас, если вы использовали не­стандартную конструкцию. Если необходимо использовать такие конструк­ции, их следует сконцентрировать в нескольких хорошо документированных модулях.

1.7. Архитектура компьютера

Поскольку мы рассматриваем языки программирования с точки зрения их практического использования, мы включаем короткий раздел по архитектуре компьютеров, чтобы согласовать минимальный набор терминов. Компьютер состоит из центрального процессора (ЦП) и памяти (рис. 1.1). Устройства вво­да-вывода могут рассматриваться как частный случай памяти.

рис. 1 . 1 . Архитектура компьютера.

Все компоненты компьютера обычно подсоединяются к общей шине. Физически шина — это набор разъемов, соединенных параллельно; логически шина — это спецификация сигналов, которые дают возможность компонен­там обмениваться данными. Как показано на рисунке, современные компьютеры могут иметь дополнительные прямые соединения между компонентами для повышения производительности (путем специализации интерфейса и расширения узких мест). С точки зрения программного обеспечения единственное различие состоит в скорости, с которой данные могут передаваться Между компонентами.

В ЦП находится набор регистров (специальных ячеек памяти), в которых выполняется вычисление. ЦП может выполнить любую хранящуюся в памя­ти команду; в ЦП есть указатель команды, который указывает на расположение очередной команды, которая будет выполняться. Команды разделены на Следующие классы.

• Доступ к памяти. Загрузить (load) содержимое слова памяти в регистр и сохранить (store) содержимое регистра в слове памяти.

• Арифметические команды типа сложить (add) и вычесть (sub). Эти дей­ствия выполняются над содержимым двух регистров (или иногда над со­держимым регистра и содержимым слова памяти). Результат остается в регистре. Например, команда

add m,N R1,N

складывает содержимое слова памяти N с содержимым регистра R1 и ос­тавляет результат в регистре.

• Сравнить и перейти. ЦП может сравнивать два значения, такие как со­держимое двух регистров; в зависимости от результата (равно, больше, и т.д.) указатель команды изменяется, переходя к другой команде. На­пример:

jump_eq R1.L1

L1: ...

заставляет ЦП продолжать вычисление с команды с меткой L1, если со-держимое R1 — ноль; в противном случае вычисление продолжается со следующей команды.

Во многих компьютерах, называемых Компьютерами с Сокращенной Системой команд команд (RISC— Reduced Instruction Set Computers), имеются только такие элементарные команды.Обосновывается это тем, что ЦП, который должен выполнять всего несколько простых команд, может быть очень быст­рым. В других компьютерах, известных как CISC (Complex Instruction Set Computers), определен Сложный Набор команд, позволяющий упростить как программирование на языке ассемблера, так и конструкцию компилятора. Обсуждение этих двух подходов выходит за рамки этой книги; у них достаточ­но много общего, так что выбор не будет иметь для нас существенного значе­ния.

Память — это набор ячеек, в которых можно хранить данные. Каждая ячейка памяти, называемая словом памяти, имеет адрес, а каждое слово состо­ит из фиксированного числа битов, обычно из 16, 32 или 64 битов. Возможно, что Компьютер умеет загружать и сохранять 8-битовые байты или двойные слова из 64 битов.

Важно знать, какие способы адресации могут использоваться в команде. Самый простой способ — непосредственная адресация, при которой операндявляется частью команды. Значением операнда может быть адрес перемен­ной, и в этом случае мы используем

нотацию С:

load R3, # 54 Загрузить значение 54 в R3 load

R2, &N Загрузить адрес N в R2

Следующий способ — это абсолютная адресация, в которой обычно ис­пользуется символический адрес переменной:

load R3,54 Загрузить содержимое адреса 54

load R4, N Загрузить содержимое переменной N

Современные компьютеры широко используют индексные регистры. Ин­дексные регистры не обязательно обособлены от регистров, используемых для вычислений; важно, что содержимое индексного регистра может ис­пользоваться для вычисления адреса операнда команды. Например:

load R3,54(R2) Загрузить содержимое addr(R2) + 54

load R4, (R1) Загрузить содержимое addr(R1) + О

где первая команда означает «загрузить в регистр R3 содержимое слова памя­ти, чей адрес получен, добавлением 54 к содержимому (индексного) регистра R2»; вторая команда — это частный случай, когда содержимое регистра R1 ис­пользуется просто как адрес слова памяти, содержимое которого загружается в R4. Индексные регистры необходимы для эффективной реализации циклов и массивов.

Кэш и виртуальная память

Одна из самых трудных проблем, стоящих перед архитекторами компьюте­ров, — это приведение в соответствие производительности ЦП и пропускной способности памяти. Быстродействие ЦП настолько велико по сравнению со временем доступа к памяти, что память не успевает поставлять данные, что­бы обеспечить непрерывную работу процессора. Для этого есть две причины: 1) в компьютере всего несколько процессоров (обычно один), и в них можно использовать самую быструю, наиболее дорогую технологию, но объем памя­ти постоянно наращивается и технология должна быть менее дорогая; 2) ско­рости настолько высоки, что ограничивающим фактором является быстрота, с которой электрический сигнал распространяется по проводам между ЦП и памятью.

Решением проблемы является использование иерархии блоков памяти, как показано на рис. 1.2. Идея состоит в том, чтобы хранить неограниченное количество команд программы и данных в относительно медленной (и недо­рогой) памяти и загружать порции необходимых команд и данных в меньший объем быстрой (и дорогой) памяти. Если в качестве медленной памяти ис пользуется диск, а в качестве быстрой памяти — обычная оперативная память с произвольным

доступом (RAM — Random Access Memory), то концепция называется виртуальной памятью или страничной памятью. Если медленной памятью является RAM, а быстрой — RAM, реализованная по более быстрой технологии, то концепция называется кэш-памятью.

Обсуждение этих концепций выходит за рамки этой книги, но програм­мист должен понимать потенциальное воздействие кэша или виртуальной па­мяти на программу, даже если функционирование этих блоков памяти обеспечивается компьютерными аппаратными средствами или операцион­ной системой и полностью невидимо для программиста. Команды и данные передаются между медленной и быстрой памятью блоками, а не отдельными словами. Это означает, что исполнение последовательно расположенных команд без переходов, так же как и обработка, последовательно располо­женных данных (например, просмотр элементов массива), должны быть на­много эффективнее, чем исполнение групп команд с переходами и обраще­ния к памяти в случайном порядке, что требует интенсивного обмена блоками информации между различными иерархическими уровнями памяти. Если вы пытаетесь улучшать эффективность программы, то следует противиться иску­шению писать куски на языках низшего уровня или ассемблере; вместо этого попытайтесь реорганизовать вычисление, приняв во внимание влияние кэша и виртуальной памяти. Перестановка операторов языка высокого уровня не воздействует на переносимость программы, хотя, конечно, улучшение эф­фективности может теряться при перенесении ее на компьютер с иной архи­тектурой.