лекции (2003) (Глазкова) (1160821), страница 3
Текст из файла (страница 3)
2.Значение.
Любой ОД имеет какое-то значение. В чем основное отличие между переменными и константами? Во времени связывания – когда значение связывается с объектом данных.
Для переменной время связывания динамическое, а для константы – статическое. Очень четко надо понимать, что представляет собой время связывания. Например, для константы значение связывается с ОД только один раз.
В связи с этим сравним похожие на первый взгляд языки С и С++. В обоих этих языках есть понятие константы.
сonst int I=1;
В чем же отличие констант в С и в С++?
С константой значение связывается 1 раз (до начала выполнения основной программы (main)).
В языке С любая константа связывается со значением на этапе загрузки или редактирования связей, но не на этапе трансляции.
В языке С++ неявно константы разбиваются как бы на 2 класса:
-
связывание происходит во время трансляции (для констант простых типов);
-
связывание происходит перед входом в main , т.е. в момент загрузки программы на счет.
Введём два понятия:
-
стандартного пролога (это некоторые действия, которые выполняются перед началом выполнения программы);
-
стандартного эпилога (это некоторые действия, которые выполняются после завершения работы программы).
Пример. Можно ли в языке С/C++ написать:
const int N=10;
и после описывать:
int a[N];
Здесь проявляется разница этих языков. В С++ такая конструкция корректна, а в С нет.
Кросс-системы программирования.
Это системы, когда сама система программирования находится на одном компьютере (на хосте), а генерирует код для других (целевых) компьютеров.
Например, одна из главных целей создания языка Ada – создание кросс-систем. Язык С сейчас является основным для кросс-систем, язык С++ - очень редко. Это связано с различием понятия константы в этих ЯП.
3.Тип данных.
ЯП делятся на 2 типа:
-
типовые (с каждым объектом данных связывается тип)
-
без типовые.
Что из себя представляет тип данных (ТД)?
ТД характеризуется множеством значений (эта точка зрения господствовала до середины 70-х годов).
Характеристика ТД как множества значений однозначно говорит, что ТД характеризуется своей структурой.
Рассмотрим структуру с двумя подобъектами:
-
некоторое целое (int);
-
некоторый массив (int[50]).
С современной точки зрения ТД характеризует содержательную роль. Множество значений же не характеризует содержательную роль.
Пусть к структуре данных stack применимы операции: Pop(s); Push(s, int); IsEmpty(s); IsFull(s) .
Перечислив же иной набор операций, уже можно моделировать линейный список.
С современной точки зрения, ТД характеризуется прежде всего набором операций и только во вторую очередь реализацией.
Т.о., ТД = множество операций + множество значений.
При этом множество значений интересно только человеку, который реализует множество операций.
А с точки зрения пользователя тип данных характеризуется исключительно множеством операций.
Абстрактные типы данных – это типы данных, в которых пользователю видно только множество операций.
4.Адрес.
Адрес имеет смысл тогда, когда речь идет о месте размещения объектов в памяти.
С этой точки зрения, адрес имеет смысл только в традиционных (фон неймановских) ЯП.
Например, в LISP – есть значение переменной, нет имени переменной и, как следствие, нет адреса.
Абстракцией понятия адреса является понятие указателя (ссылки).
Некоторые объекты данных адреса могут и не иметь(например, константа). В языках С/C++ константы не относятся к значениям, которые могут появляться в левой части оператора присваивания.
Константа может не иметь адреса, если используется режим непосредственной адресации, т.е. когда константа расположена непосредственно в команде (например, в ассемблере mov ax,5)
5.Время жизни.
В большинстве ЯП выделяют 3 варианта времени жизни:
-
программа (ОД этого типа существует все время, пока работает программа)
-
блок (определено для блочных ЯП: при входе в блок переменные начинают жить, при выходе - перестают)
-
управляется программистом (есть явный оператор начала и конца жизни соответствующей переменной)
Время жизни отождествляется с атрибутом класс памяти. Это понятие связано с понятием реализации. Выделяют 3 класса памяти в современных ЯП:
-
статическая
-
квазистатическая
-
динамическая
С точки зрения реализации удобно реализовывать объекты данных этих 3 видов ( с 3 разными временами жизни), именно относя их к разным областям памяти.
-
Статическая память – это память, объекты которой существуют все время работы программы. Основная характеристика статической области памяти: там связывание адреса и положения происходит один раз в момент загрузки программы за время работы программы не меняется. Поэтому переменные, которые живут все время жизни программы, удобно размещать именно в статической памяти.
-
Квазистатическая (стековая) память – явным образом реализовано понятие стека в машинной архитектуре. Квазистатические объекты размещаются в стеке. Переменные, которые отводятся в блоке, удобно отождествлять с переменными, которые размещаются в стеке. Статические и квазистатические объекты похожи друг на друга. Например, в языке С, когда мы делаем объявление int a; мы не можем вне контекста сказать, статический или квазистатический это объект.
-
Динамическая память. Переменные, временем жизни которых управляет программист, размещаются в динамической памяти. Это те переменные, ссылка на которые возможна только посредством какого-то указателя.
6.Область видимости.
Область видимости связана с понятием имени.
У любого имени должно быть определение. Есть 2 вида вхождения имени:
-
Определяющее вхождение имени – это определение и объявление. В С и С++ определение и объявление - это разные понятия (например, int a; - это определение переменной а ; extern int a; - это объявление переменной а). Другой пример : прототип функции – это объявление функции; а прототип функции, за которым следует блок, – это определение функции. Определение – это всегда определяющее вхождение имени. Объявление также может быть определяющим вхождением имени.
-
Использующее вхождение имени. Для большинства имен должно существовать одно определяющее вхождение имени и много использующих. (Например, a=3; - это использующее вхождение имени).
Область видимости – это область программы, в течение которой действует определяющее вхождение имени.
(Например, блок, класс, модуль – области видимости.)
Ключевой вопрос – каким образом использующее вхождение связывается с определяющим?
Области видимости (ОВ):
-
Статические ОВ (связывание использующего и определяющего вхождения происходит в момент трансляции или редактирования связей, т.е. до момента выполнения программы).
-
Динамические ОВ (связь использующего и определяющего вхождения осуществляется во время выполнения программы).
Поясним это на примере.
Рассмотрим гипотетический ЯП, в котором есть понятие модуля и процедуры.
Модуль М
int i1=2;
proc P1;
begin
i=1;
end P1;
proc Р2;
int i2;
begin
P1;
end P2;
Области видимости в этом фрагменте:
Модуля – M,i1,P1,P2
Процедуры –
-
P1 - i1=1; - использующее вхождение.
-
P2 - i2.
При статическом связывании привязка адреса происходит до выполнения программы, исходя из принципа вложенности. При статическом связывании областей видимости i=1; соотносится с i1, т.е. i1=1.
Динамическое связывание областей видимости.
В этом случае мы не можем сказать, с чем соотносится i=1; Представим 2 ситуации
-
вызывается процедура Р1 из модуля М. В память загружается i1 и Р1. При динамическом связывании в момент вызова Р1 начинается поиск по областям видимости => i1=1;
-
выполняется процедура Р2. Вначале загружается i1 из модуля М, затем загружается Р2 (там находится i2). После этого из Р2 мы вызываем Р1 => i2=1;
Итак, семантика вызова зависит от динамической последовательности вызовов. Следовательно, при динамическом связывании связывание соответствующих областей видимости происходит во время выполнения.
Чем хороша статическая область видимости? Привязка адреса происходит во время трансляции программы
При динамическом связывании адрес определяется во время выполнения программы (т.е. происходит поиск по таблицам, что влечет дополнительные накладные расходы), но программирование становится более гибким.
Классификация времен связывания.
-
статическое связывание (время связывания – до момента выполнения программы - во время трансляции; во время редактирования связей; во время загрузки);
-
динамическое связывание (связывание во время выполнения программы – статическое; квазистатическое; динамическое);
-
время реализации языка;
-
время определения (разработка) языка.
Пример.
Рассмотрим оператор присваивания: X=X+10;
-
Связывание имени X и типа данных (если это язык С, то это происходит на стадии трансляции(статическое связывание)).
-
Связывание Х и множества значений (это происходит на этапе реализации языка (в языке Java это происходит на стадии разработки языка)).
-
Связывание Х и значения переменной Х (динамическое связывание).
-
Представление константы 10 (статическое связывание ( как правило, в момент трансляции, либо в момент загрузки)).
-
Множество возможных типов для переменной Х (устанавливается на этапе разработки языка).
-
Связывание со смыслом операции + (в языке Java,C – статическое связывание во время трансляции; в С++ - во время загрузки).
Лекция 5.
Часть 1. Традиционные ЯП.
Тенденция развития современных ЯП.
ЯП подразделяются на языки, которые не требуют совместимости с предыдущими программами (С#, Java), и языки, которые требуют совместимость (Delphi, C++).
Интересно, что тенденция мобильности знаний осуществляется и при проектировании новых ЯП.
Тенденция современных ЯП такова, что новые ЯП концептуально опираются на уже разработанные языки.
К процедурной парадигме добавляются понятия классов и ООР парадигма программирования. Поэтому мы не будем рассматривать именно традиционные ЯП, подразумевая «старые» ЯП (Algol, Fortran, Cobol и т.д.), мы будем рассматривать современные ЯП, а именно те их конструкции, которые унаследованы из традиционных ЯП.
Вначале вспомним концептуальную схему рассмотрения ЯП:
-
базис (скалярный(примитивные ТД и операции над ними) и структурный (составные ТД, множества, управляющие структуры); тенденция современных ЯП – сужать базис);
-
средства развития – новые абстракции.
-
аппарат защиты – это средства, которые поддерживают цельность создаваемых абстракций.
Начинаем с рассмотрения базиса (он в традиционных и ООР ЯП почти одинаковый), затем рассмотрим средства развития (а именно, понятие модуля и класса, связанный с ними аппарат абстракций и инкапсуляций ), а также связанные вопросы (статическая параметризация и аппарат обработки исключений)).
Подчеркнем еще раз тот факт, что большая часть языковых конструкций унаследована из традиционных ЯП.
Глава 1.
Простые типы данных (ПТД).
Мы начинаем с рассмотрения базиса. Сначала рассмотрим скалярный базис, т.е. простые (атомарные) ТД. Все значения простых ТД являются атомарными - они не имеют внутренней структуры (т.е. она может появляться (например, битовая структура вещественного числа), но не на уровне языка, а на уровне реализации).
Простые ТД подразделяются на:
-
арифметические (целые и вещественные) ;
-
символьные;
-
логические;
-
порядковые (перечисления и диапазоны);
-
ссылочные (указательные) типы;
-
процедурные.
Пример 1. Рассмотрим ЯП Pascal (стандартный).