Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Яп

.pdf
Скачиваний:
28
Добавлен:
15.03.2023
Размер:
6.44 Mб
Скачать

2/27/2023

 

 

 

Оптимизатор кода

 

1. Машинно-зависимаяоптимизация – использование

 

регистров процессора вместо оперативнойпамяти.

2. Машинно-независимаяоптимизация – оптимизация

 

промежуточногопредставления программы.

 

3. Локальнаяоптимизация– замена нескольких команд

 

однойболеебыстрой.

 

 

4.

Глобальнаяоптимизация – оптимизациявсей

 

 

программыза счет замены на более быстрые

 

 

инструкции.

 

 

 

 

• Отладку лучше проводитьпривыключенной

 

 

оптимизации, а тестирование – два раза (и при

 

включенной и привыключенной).

 

 

 

 

 

 

 

81

Этапы подготовки программы к выполнению

Исходный

Макро-

 

Исходный

Ассемблер

 

модуль

 

модуль 2

или

 

процессор

 

 

 

 

компилятор

 

 

 

 

 

 

 

 

 

Объектный

 

Редактор

Загрузочный

Загрузчик

 

 

 

связей

 

 

модуль

 

модуль

 

 

 

 

 

 

 

 

 

 

Связыва-

 

 

 

 

 

ющий

 

Выполнение

 

 

 

 

загрузчик

 

 

 

Интерпре-

 

 

 

 

 

 

татор

 

 

 

 

 

 

 

 

 

 

83

Процесс трансляции

ИСХОДНАЯ ПРОГРАММА

Лексический анализатор

Синтаксический анализатор

Диспетчер

Семантический анализатор

 

 

Обработчик

таблицы

 

символов

Генератор промежуточного

ошибок

 

кода

 

Оптимизатор кода

Генерация целевого кода,

обычно перемещаемого Генератор кода машинного кода или

ассемблерного кода

ЦЕЛЕВАЯ ПРОГРАММА

82

ТИПЫ ДАННЫХ И ТИПИЗАЦИЯ

84

21

Типы данных

Для хранения данных используются ячейки памяти = 8 бит = 1 Байт

В зависимости от разрядности процессора оптимальными для обработки становятся большие объемы данных – 16 бит (2 Байта), 32 бита (4 Байта), 64 бит (8 Байт), 128 бит (16 Байт).

Такой минимальный для процессора объем одной ячейки называют машинным словом.

Тип данных – механизм классификации данных.

В каждом языке имеется набор встроенных типов данных.

Дополнительно в языке предусматриваются средства, позволяющие программисту создавать новые типы данных.

Современный подход - язык должен предоставлять средства для расширения набора типов данных.

Типы данных делятся на:

1.

Простые

 

2.

Составные

85

Атрибуты (характеристики) объекта данных

Тип. Задаетвозможные значения, применимые операции и формат хранения данных.

Местоположение - Координаты областипамяти, отведенной под объект данных. Назначаютсясистемными программными средствами,управляющими памятью. Программист обычно не имеет доступа к этим средствам.

Значение. Это текущая величина(набор величин) объекта данных.

Имя. Перечень имен, по которым к объекту данных обращаются в процессе вычислений.Могут назначатьсякак статически в начале работы, так и динамически, в определенные моменты времени вычислений.

Принадлежность. Сведения о принадлежности данного объекта к другим объектам данных (например, ссылкина эти объекты).

Адрес. Указываетячейку(и) памяти под переменную.

Время жизни. Период существованияобъекта в программе.

Область видимости. Это сегмент, фрагмент программы, в пределах

которой доступен объект.

87

 

2/27/2023

Объекты данных

Каждый язык программирования задает три категории характеристик:

1) допустимые значения данных и способыразмещения значений в памяти компьютера;

2) допустимыеоперации (встроенные в язык и рукотворные, то есть создаваемые программистом);

3) операторы, управляющие последовательностью примененияопераций к данным.

Элементыданных,рассматриваемые как единоецелое в некий моментвыполненияпрограммы,называют объектами данных.

Объектданных является контейнером,содержащим значения данных и другую информациюо данных.

Содержаниеатрибутов объекта данных находится в той части

его контейнера, которая называется дескриптором.

86

Система типизации данных

Сумму правил, связанных с типами данных и их экземплярами, объединяют в понятие система типизации данных.

Системы типизации данных определяют полный жизненный цикл объектов данных в программных вычислениях и включают в себя несколько категорий правил:

1.определения атрибутов переменных, их связывания;

2.определения типов данных;

3.определения типов выражений;

4.правила преобразования и проверки типов данных.

88

22

Типы данных

Каждая переменная (константа) считается экземпляром типа.

Знание типа переменной позволяет решать следующие вопросы:

1.можно или нельзя присвоить переменной конкретное значение;

2.можно или нельзя применить к переменной какую-то операцию.

Тип данных определяет: 1. значения объектов;

2. операции, применимые к значениям;

3. размещение значений в машинной памяти.

Тип данных — это двойка

<Тип_данных> =< <Алгебра_операций>, <Формат_размещения_значений> >

где

<Алгебра_операций> = (<Значения>, <Операции>)

89

СВЯЗЫВАНИЕ ПЕРЕМЕННЫХ

91

2/27/2023

Реализация типа данных

• При реализации типа данных обычно рассматриваются:

1.способ представления объектов данных этого типа в памяти компьютера (в процессе вычислений);

2.способ представления операций, определенных для этого типа данных. Задает конкретные алгоритмы и процедуры для обработки выбранной формы размещения объектов данных в памяти.

Реализация типа данных определяет, каким образом данные виртуальной среды вычислений отображаются на аппаратные и программные средства компьютера.

Синтаксис атрибутов типа данных определяется формой объявления типа, принятой в языке.

Значения представляются литералами или именованными const.

Вызов операций задается при помощи специальных символов, встроенных процедур или функций.

При этом компилятор решает две задачи:

1.максимально эффективно разместить данные в памяти;

90

2. проверить соответствие данных указанному типу.

Связывание переменных

Связывание (binding) — это процесс установления связи между атрибутами. Момент времени, когда эта связь устанавливается,

называют временем связывания.

Связывание может происходить

1.во время проектирования языка,

2.при разработке компилятора языка,

3.при компиляции,

4.при загрузке или выполнении программы.

• Связывание типа — имя связывается с типом:

var

x : integer;

/* Pascal*/

int

y;

/* С */

92

23

Связывание переменных

• Связывание значения — имя связывается со значением: x:= 15; /* Pascal*/

y = 25; /* С */

По времени различают две разновидности связывания:

статическое и динамическое.

Статическое связывание - выполняется в период компиляции

Динамическое связывание - в период выполнения программы.

93

Статическое связывание

Неявные объявленияобъявленияпо умолчанию, применяютсялишь тогда,когдаотсутствуютявныеобъявления.

Например,

1.в программенаязыкеFortran можноиспользовать простую переменнуюс именемNUMBER,не объявляяее явным образом. Компиляторпо умолчаниюсчитает, что эта переменнаяимеет целыйтип INTEGER, так какее имя начинаетсяс буквы,входящей в переченьI, J, K, L, M, N. В противномслучае переменнойбыл бы приписан вещественныйтип REAL.

2.в языкеPerl все переменныес именами,начинающимисяс символа $, считаютсяскалярнымивеличинами,которые могут быть строкамиили числами.Еслиимя начинаетсяс символа @, то именуемаяпеременнаяявляетсямассивом; если имяначинаетсяс символа %, то оно обозначает хешированнуюструктуру.

95

2/27/2023

Статическое связывание

• Статическое связывание – за счет явных и неявных объявлений.

1.Явное объявление - оператор программы, сообщающий компилятору сведения об именах и типах объектов данных, которые применяются в программе. Место размещения объявления в программе определяет время жизни объекта.

float х, у; // во время выполнения функции потребуется два объекта данных типа float с именами х и у. Время жизни объекта х и объекта у ограничено периодом работы функции. После завершения выполнения функции эти объекты уничтожаются.

2. Логический вывод типа

 

var sum = 0;

// Здесь типами переменных sum

var total= 0.0;

// total и name становятся int, float

var name = "Liza";

// и string соответственно.

94

Динамическое связывание

При динамическомсвязыванииоператор объявления переменнойне содержит именитипа.

Типпеременнойопределяется при присвоениией значения оператором присваивания. При выполнении оператора присваиванияпеременная из его левой частиполучаеттип

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

Динамическоесвязываниепостулирует:любой переменной можетбыть присвоено значениелюбого типа.

Во время выполнения программытип переменнойможет меняться многократно.

Важнопонимать,что тип у переменнойс динамически связанным типомимеетлишь временный характер.

Основноепреимуществодинамическогосвязывания переменных с типомзаключается в повышениигибкости программирования.

96

24

Динамическое связывание

Снижается надежность программ, т.к. возможности обнаружения ошибок меньшие, чем для языка со статическим связыванием.

Высокая стоимость реализации, особенно во время вычислений.

Каждая переменная несет в себе сложный дескриптор. Для хранения любой переменной задействуется область памяти переменного размера, поскольку формат сохраняемого значения меняется от типа к типу.

Как правило используются интерпретаторы = > программы работают дольше.

Используется в языках Python, Ruby, JavaScript и PHP.

Например, программа на языке JavaScript:

list = [4.3, 8.2]; // сейчас одномерный массив вещественных чисел list = 75; // станет целочисленной скалярной переменной

Например, C# версии 2010 года. Включение в объявление

 

переменной зарезервированного слова dynamic разрешает

 

динамическое связывание типа:

 

dynamic any;

97

Типы переменных в зависимости от связывания

Стековыми называются переменные,удовлетворяющие двум условиям: связывание с памятью осуществляется при обработке операторов объявления переменных; типы переменныхсвязываются статически.

+все подпрограммы могут совместноиспользовать одну и ту же область памяти для хранения своих локальных переменных.

-дополнительные затраты временина размещение в памяти и удаление из памяти;

-уменьшение скорости доступа из-за использования косвенной адресации;

-подпрограммы не имеют возможности хранить предысторию вычислений.

В языках Java, С++ и C# локальные переменныев методах становятсястековыми переменнымипо умолчанию.

99

2/27/2023

Типы переменных в зависимости от связывания

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

В языках С и С++ разрешается спецификатор static в объявлении локальных переменных для функции; соответствующие переменные при этомсчитаются статическими.

Применение static для объявления переменной в классе C++, Java и C# означает, что переменная становится переменной класса, а не переменной экземпляра(объекта).

Переменные класса создаются статически за некоторое время до начальной инициализации класса.

98

Типы переменных в зависимости от связывания

Явные динамические переменные - безымянные ячейки памяти,

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

Обращаться к этим переменным можно только с помощью указателей и ссылок. Переменные хранятся в динамической памяти куче (heap).

Явные динамические переменные создаются или оператором, или вызовом предусмотренной библиотечной подпрограммы.

int pointer;

// создать указатель

pointer = new int;

// создать явную динамическую переменную

delete pointer;

// удалить явную динамическую переменную,

//на которую указывает указатель pointer

В языке Java все данные, за исключением основных скалярных величин, являются явными динамическими объектами, доступными через ссылочные переменные.

В языке C# имеются как явные динамические, так и стековые объекты, все они удаляются неявно.

100

25

Типы переменных в зависимости от связывания

Неявные динамические переменные связываются с динамической памятью только при присваивании им значений. Фактически все их атрибуты и характеристики вновь связываются при каждом присвоении переменной нового значения.

JavaScript:

volumes = [24, 94, 76, 50, 41]; Независимо от того,

использовалась ли переменная volumes раньше и для чего она использовалась, теперь это массив из пяти числовых значений.

+высокая степень гибкости, позволяющая писать обобщенные программы.

-высокие накладные расходы на обслуживание всех динамических атрибутов, среди которых могут быть: тип элементов массива, диапазон индексов и многие другие.

-потеря компилятором возможностей распознавания многих ошибок.

101

Контроль типов

Контрольтиповпроверяет факт получениякаждойоперацией (в программе) нужногоколичестваоперандовправильного типа.

Контрольтиповможет осуществлятьсяв периодвыполнения программы(динамическийконтроль типов) или в период компиляции(статическийконтрольтипов).

Статическийконтрольтипов

• Исходныеданные:

1.Для каждойоперации определены количествои типы данных для операндови результата.

2.Типкаждогообъектаданных (переменной или экземпляра типа) известен и не меняетсяв ходе выполненияпрограммы.

3.Типывсех константтожепонятны.

103

2/27/2023

КОНТРОЛЬ ТИПОВ

102

Алгоритм статического контроля типов

1.Компилятор собирает информацию при анализе текста программы и заносит в таблицу символов, которая накапливает все сведения о типах переменных и операций.

2.После завершения сбора компилятор проверяетвсе операции программы на предметправильности типов их операндов.

3.После проверки типов операндов i-йоперации определяется типее результата,а полученная информация сохраняетсядля проверки следующей, (i+1)-йоперации программы, в которой результат i-й операции может использоваться как операнд.

Статический контроль типов охватывает все операции программы => проверке подвергаютсявсе варианты вычислений и отпадает необходимость в дальнейшем

контроле. 104

26

Динамический контроль типов

Осуществляется непосредственно перед выполнением.

Динамический контроль типов характерен для скриптовых, функциональных и логических языков.

+Гибкость программы. Так как объявлений типов нет, объект данных может поменять свой тип в любоймомент вычислений.

+Можно создавать настраиваемые программы, способные работать с данными любого типа.

-Понижение надежности вычислений. Работа над возможными ошибками типизациипереносится на этап вычислений. Многие из объектов остаются вне контроля.

-Снижение скорости вычислений. Динамическийконтроль типов основан на информации,которая хранится в дескрипторах объектов данных. Как правило, доступ к дескрипторам должен быть реализованна программном уровне, так как аппаратура таких действий не обеспечивает. Это выливается в существенное замедление скорости вычислений.

-Возрастание накладных затрат памяти. Поскольку каждый объект данных несет в себе сложный дескриптор, который содержит обширные сведения и должен храниться в течение всего вычислительного процесса, динамический контроль типов предъявляет повышенные запросы к требуемой памяти.105

Типы данных

Простые типы данных (элементарные): 1. Целочисленные 2. Вещественные 3. Символьные 4. Логические 5. Перечисления

Составные типыданных:

1.Массивы

2.Структуры и записи

3.Строки

4.Множества

5.Кортежи

6. Классы

107

2/27/2023

КЛАССИФИКАЦИЯ ТИПОВ ДАННЫХ

106

Целочисленные типы данных

Числа со знаком представляются в виде дополнительного кода. Положительные – 0 и двоичное число, отрицательные – инверсия битов и добавление единицы.

Самое большое положительное целое число, которое может быть

представлено словом из w битов 2w 1 1

Машинно-независимые типы – количество байт соответствующих им ячеек памяти строго фиксированы и не зависят от процессора, на котором исполняется программа и компилятора, который создал машинный код.

Примеры типов данных: char (1 Байт).

Машинно-зависимые типы – размер занимаемых ими ячеек зависит от платформы, под которую компилируется.

Примеры типов: int – ровно одно машинное слово. 32-битная платформа – 4 Байта, 64-битная – 8 Байт.

Нюансы при записи данных в двоичные файлы на разных

платформах

108

27

Целочисленные типы данных

109

Операции над целыми числами

Операция умножения требует большего времени выполнения на процессоре.

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

Операция деления разделена на

1.получение целой части ( / div)

2.получение остатка от деления (% mod). Требует самого большого числа тактов.

111

2/27/2023

Операции над целыми числами

Основные: сложение, вычитание, умножение деление. Приоритеты – как в математике.

Получаемые значения ограничены диапазоном типа данных. char a,b,c;

a=200;

b=56;

c=a+b; // с будет равно единице

Переполнение – полученное значение выходит за границы допустимого диапазона данных.

Часто переполнение обрабатывается согласно цикличной арифметики – отбрасывается кратное число предельно допустимых значений и оставляет остаток.

Стоит опасаться действий оптимизатора:

c = a – 100 + b;

тут все логично

 

c = a + b – 100;

оптимизатор преобразует вот так и будет

;

переполнение

110

 

 

Особенности целых типов с С++

Целочисленные операции выполняются быстро в большинстве случаев, независимо от размера. Но неэффективно использовать переменные размера больше, чем размер регистра.

Обычно int – наиболее эффективный размер на данной системе, рекомендуется использовать его, если нет опасности переполнения. Типы меньшего размера (char, short int) немного менее эффективны. Компилятор конвертирует их в int, выполняет над ними операции, а затем берет младшую часть результата (1 такт)

На 64-битных системах есть минимальное различие между эффективностью 32-битных и 64-битных целых, если не использовать деление.

Беззнаковый целочисленный тип size_t (32 бита или 64 бита). Он используется для хранения размеров и индексов массивов,

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

Автоматической проверки на целочисленное переполнение нет112.

28

Особенности целых типов с С++

Знаковые и беззнаковые целые

В большинстве случаев нет разницы между знаковыми и беззнаковыми целыми значениями. Исключения:

1.Деление (взятие остатка от деления) на константу: беззнаковое быстрее.

2.Преобразование к вещественному значению: знаковое быстрее.

3.Различное поведение при переполнении.

Преобразование между знаковым и беззнаковым значениями ничего не стоит – это только смена интерпретации.

inta, b; double c;

b = (unsigned int)a / 10; // Convert to unsigned for fast division c = a * 2.5; // Use signed when converting to double

• Нельзя сравнивать знаковые и беззнаковые значения, т.к. результат

неоднозначный.

113

Особенности целых типов с С++

Операторы инкремента и декремента

Операторы инкремента так же быстры, как сложение.

В простом случае пре-инкремент и пост-инкремент реализуются одинаково, и обычно нет разницы.

Но

x= array[i++]; более эффективно

x= array[++i]; вычисление адреса должно ждать

;нового значения i.

a = ++b; // компилятор распознает, что значения a и b совпадают, и может использовать для них один регистр.

a = b++; // значения переменных разные, и один регистр использовать нельзя => работает дольше

• Все то же самое верно и для оператора декремента.

115

2/27/2023

Особенности целых типов с С++

Целочисленные операторы

Целочисленные операторы очень быстрые. Простые операции (сложение, вычитание, сравнение, битовые операции и сдвиги) занимают один такт на большинстве микропроцессоров.

Умножение и деление занимают более долгое время.

Целочисленное умножение занимает 11 тактов на Pentium 4 и 3-4 такта на большинстве современных процессоров.

Целочисленное деление занимает 40-80 тактов, в зависимости от процессора. На процессорах AMD целочисленное деление тем быстрее, чем меньше размер типа данных.

114

Преинкремент и постинкремент

<?php

for($i=0; $i<50000; ++$i) { print $i.'<br />';

}

?>

Время работы: 0.016938924789429

<?php

for($i=0; $i<50000; $i++) { print $i.'<br />';

}

?>

Время работы: 0.018353939056396

116

29

Вещественные числа

• Представляются следующим образом:

10,112 1 21 0 20 1 2 1 1 2 2 2,7510

Обратный переход затруднен, т.к. не каждое десятичное можно перевести в конечные двоичные числа

Два подхода к двоичному представлению вещественных чисел:

1.Согласно двоичной арифметике – двоично-кодированные десятичные числа (BCD – binary-coded decimal).

2.Кодировать цифры числа как целое число, дополняя информацией о позиции десятичного разделителя.

117

Числа с плавающей точкой (float)

Любое число можно представить в экспоненциальном виде:

Вещественное число в интервале [0; 1].

Количество возможных цифр в целой части фиксируется.

Т.к. мантисса всегда меньше 1, то позицию точки хранить не надо.

Кол-во знаков мантиссы определяет относительную погрешность.

Очень широкий диапазон чисел, низкая относительная погрешность.

Операции умножения могут приводить к тому, что порядок в результате вычисления выйдет за границы допустимого диапазона:

Переполнение – порядок выше верхней границы диапазона.

Потеря значимости – порядок меньше нижней границы диапазона.

119

2/27/2023

Числа с фиксированной точкой (fixed)

Формат числа с фиксированной точкой определяет, что вещественное число содержит не более заданного количества цифр N целой части и не более некоторого заданного количества M цифр после запятой, итого N+M.

Достаточно сохранить его целочисленное представление (включая 1 бит знака) и номер позиции десятичной точки.

Количество знаков после запятой определяет абсолютную погрешность.

 

Относительная погрешность переменная.

 

Некоторые числа нельзя вписать в формат.

 

Применяется когда точность заранее определена: денежные

 

 

операции, показания приборов

118

Операции с вещественными числами

Умножениеи деление

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

Чтобыпроизвестиделение нужно разделить мантиссу делимогона мантиссуделителя и вычесть изпорядка делимогопорядок делителя.Затемточно так жеокруглить мантиссурезультатаи привестиего к нормализованной форме.

Сложениеи вычитание

Сначала выбираетсяоптимальныйпорядок,затем мантиссы обоихчисел представляются в соответствиис новым порядком,затем над ними производится сложение/вычитание,мантиссарезультатаокругляетсяи, если нужно,результатприводитсяк нормализированнойформе.120

30