лекции (2007) (1160825), страница 4
Текст из файла (страница 4)
a=x;
Что если в языке С++ определить, что в некотором классе X имплементирован метод Ф, и в то же время, класс X включает в себя класс X1, в котором имплементирован метод Ф1.
В С++ нельзя сделать X->Ф1 (а в SmallTalk это пройдет) – статическая область видимости. Но для объектов-исключений вводятся динамические области видимости. В современных ЯП реализован аппарат обработки исключений. Сначала он был реализован в Языке Ада, а все остальные языки при своём создании ориентировались на С++.
Место в памяти – Данные и операция – высокоуровневая абстракция, команда – аналог операции.
Что такое данные? Нечто, с чем можно выполнять операции. Если мы не можем с ним выполнять операции, оно не является данным. Операции – то, что можно выполнить с данным. Совершенно невозможно выделить, что из них первично, а что вторично.
Существует дуализм операций и данных. Что такое класс? Модуль - коллекция ресурсов. Класс – тип данных. Объекты класса являются данными. Является ли класс модулем? Да, представим себе класс, в котором есть только статические данные. Он ничем от UNIT не отличается.
class M{
static int f();
static int i;
.
.
}
M::F();
M::X; //а в паскале m.f и m.x
Рассмотрим тип данных – строку. Над этим типом данных определяется операция length. Только что это, функция? В ряде случаев, она нам возвращает число как данное.
В Windows есть тип BSTR (совокупность символов, заканчивающаяся 0). strlen(s); - по построению есть операция, но она же и данное. wcslen(s); - безусловно операция.
Вспомним Pascal
S: string;
Cтрока имела длину до 256 символов. И в 0 байте была длина строки.
S:string;
len:byte absolute S;
B тут len и length(s) эквивалентны.
Наиболее универсальный способ – писать как данные.
С современной точки зрения (инженерной), тип данных – совокупность множества значений, в некотором смысле структура данных, сопровождаемая функциональным интерфейсом. С точки зрения пользователя, мы абстрагируемся от данных.
Но это есть и плюс (единство и абстрагированность интерфейсов для драйверов)
Данные, операции и связывания
Дуализм данных. Множество значений и операций.
Property – в Дельфи и С#
С точки зрения программиста – пользователя – тип данных.
Окно (х, у, ширина и высота)
SetWindowPos() И GetWindowPos() – что это?
Comp.x=0; - с точки зрения программиста это присваивание типа данных. А с точки зрения архитектуры – процедура.
С инженерной точки зрения основополагающим является множество операций. Даже то, что свойства выглядят, как данные. На самом деле это операция. Даже в типе int есть getter и setter, которые вызываются автоматически. Концепция АТД – если мы меняем множество значений, не меняем реализацию. При внесении изменений в реализацию, изменения в ПО уменьшаются.
Понятие связывания.
Ситуация связывания и момент связывания. Чаще всего будут интересовать статическое и динамическое связывание (во время работы). В Pascal и C переменные с динамическим связыванием, а константы - со статическим. Константы в основной своей массе обладают статическим связыванием, но в Аде константа может быть связана статически, но 1 раз:
X: T constant:=e;
В С# константы – статическое связывание, readonly – динамическое.
Пример
Class X
{
Virtual void f();
};
Class Y: public X
{
Virtual void f();
Virtual void f1();
};
Здесь происходит 2 связывания. Первое – поиск сигнатуры, второе – связывание функции с определением, телом соответствующей функции. Связывание уже найденной сигнатуры с телом – динамически. А если бы не было слова virtual – связывание было бы статическим
В С++ динамическое связывание происходит на этапе выполнения. А статическое - у линковщика.
Основные понятия традиционных языков индустриального программирования
Базис
Средства развития
Средства защиты
Базис в свою очередь делится на скалярный и структурный.
Глава 1. Простые типы данных
-
Арифметические
Язык lua – скриптовый язык, но тут есть свои особенности. Он хотя и базовый, но он конечный.
Классификация:
- Целые типы
- Вещественные типы (они тоже делятся на плавающие и фиксированные(Float и double)) Если взять Аду, в ней есть плавающие типы, а есть и целые. Фиксированные типы – типы с фиксированной точки. Точность в них фиксирована.
- символьные
- логические
- диапазоны
- перечисления
Как правило, диапазоны и перечисления объединяют в 1.
- указатели и ссылки
Int * f() { }
Int & f() { }
И то, и другое суть адрес. Но первое возвращает NULL. А вторая NULL не умеет, но зато есть аппарат исключений.
1. Арифметические типы данных
1.1 Целые типы данных
В этом случае, мы сталкиваемся с компромиссом – эффективность против универсальности (легкость изменения, портируемость)
В С, С++ и Ада не фиксируется представление чисел. Вместо этого в С зафиксирована номенклатура. Основной тип – int, но он максимально использует возможности процессора. Вот и есть 4 типа: Int, short, long, char. В разных архитектурах устанавливаются разные соотношения между ними. Но что считать в 64-битной архитектуре типом int (чистый 64-битный процессор – Itanium). А режим совместимости делался только из-за программной эмуляции. Появилась промежуточная архитектура IA-32/64 из-за проблем совместимости. 64 бита оставлены только для того, чтобы адресовать. 32 бита – размерность арифметических операций. Получилось, что языки, ориентированные на одну платформу, фиксируют представление всего и вся, но делают широкую номенклатуру. SBYTE, USHOT, UINT, ULONG и их удлиненные типы – вот вся номенклатура. Char в C# -отдельный тип данных.
В Java с точки зрения арифметики, есть тип данных byte, short, int, long. Первое, что сделали в Java – зафиксировали эти типы. Из-за принципа Write Once Use Anywhere.
Проблема с int и char
C=getchar() (когда -1 преобразуется в 255).
Зачем беззнаковая арифметика? Она необходима, так как существуют операции с адресами.
В Modula 2 был тип данных INTEGER. В первой реализации он был 16-битным. И отдельно был тип CARDINAL – беззнаковый. Первый компилятор C Front не прошел проверки на неявные преобразования из unsigned int в int. C++ поэтому язык для программистов. Его нельзя использовать для обучения. В С и С++ возникает ненадежность с этими типами. А с другими языками – кто как хотел. В Oberon например вообще убрали тип беззнаковый. BYTE – SHOTINT – INTEGER – LONGINT
Типы данных и подтипы.
Идея в том, что типы данных между собой несовместимы.
Type POSITIVE is new INTEGER range 0 .. MAXINT;
Type NATURAL is new INTEGER range 1 .. MAXINT;
Эти типы с INTEGER несовместимы. А если мы хотим использовать совместимость, то мы должны использовать подтипы и контроль совместимости – статический или квазистатический.
Subtype CARDINAL is INTEGER range 0 ... MAXINT;
C - CARDINAL
I - INTEGER
I:=C – нет проверки
C:=I – квазистатическая проверка
В это время, если P типа POSITIVE – P:=I, I:=P - недопустимы
Квазистатическая проверка – проверка, когда если компилятор не знает заранее значения, переносит ее на время выполнения.
1.2 Вещественные типы
- плавающие типы(floating)
- фиксированные типы
Плавающий тип - тип с мантиссой. +(-) M*B^p
В основном, B=2, но бывают и другие значения.
В современных ЯП семантика плавающих типах более-менее зафиксирована
стандартом IEEE 794. IEEE стандарты не навязываются, но они сразу принимаются всеми. Производители и разработчики языков стали ориентироваться на него. В соответствие с 794, числа хранятся в нормализованном виде, В=2, 1/B<=M<1 (пример неоднозначности с 1/2 либо 2^(-1), либо ½*2^0). Есть 32-разрядное число, есть 64-разрядное. В основном, 1 бит под знак, 8 под порядок. Представление вещественных числе избыточно(+0 и -0), кроме того некоторые значения порядка зарезервированы. Можно использовать от -126 до 126. Арифметика в этом стандарте допускает NaN, существует + и - бесконечность, потом + бесконечность, умноженная на -1 = - бесконечность. Плюс к тому, еще не может получиться -0. Разработчики ЯП сказали, что их стандарт 794. Поэтому в Java float соответствует 32 битному стандарту, double соответствует 64 битному. Но этой арифметики недостаточно. В мощных суперкомпьютерах есть 128 и 80-битные числа.
Рассмотрим, сколько чисел может быть между 1/2 и 1 в 32 битной. Итого, чисел 2^23, точность 2^(-24).
Если взять диапазон от 1 до 2 - столько же чисел - 2^23. Далее - между 2 и 4 – 2^23 чисел. В итоге, расстояние между числами увеличивается в 2 раза. Это за счет того, что в мантиссе 23 бита, так что если мы оперируем в числах порядка миллиона, погрешность уже заметна. Точность 10^(-6). Если числа больше, чем 2^20 - не любое число мы можем туда записать. В ряде случаев представление в числах с плавающим типом невозможно.
Ряд языков игнорирует понятие фиксированного типа. Например, в Java оно эффективно только если оно кладется на соответствующую архитектуру. Поэтому этот тип вынесен в стандартный класс.
Когда мы описываем в Аде плавающий тип, мы указываем относительную точность.
type real is digits 6;
type name is digits D;
Можно было указать и переменную. Далее компилятор сводит это к тому, что есть модельные числа, которые включают в себя это число. Как оно работает:
Число бит в мантиссе b=[log D] +1; -4*b<=p<=4*b. Эти модельные числа включают в себя нужные вещественные. Теперь надо подобрать имеющийся в компьютере тип данных, чтобы он подходил. Если подходит, то используем его. Первый язык Ада делал то, что если не находил бы такого типа, то сначала делалась программная эмуляция, но потом это стало очень неэффективно. Теперь требования
ослабились. Теперь снимается нагрузка с программиста, компилятор сам находит подходящую ему реализацию.
Дельта типы данных
type T is delta H range l..f; - разница между двумя соседними числами. Вот эти выражения должны быть статическими константными выражениями. В Аде считается, что существует универсальный вещественный тип данных, который покрывает все числа.
Эти 2 числа относятся к этому универсальному типу.
type dTemperature is delta 200|2**12 range -100.0 .. 100.0;
Отметим, что в современных ЯП нет фиксированных чисел, но есть исключение. С# имеет тип decimal. Все остальные типы данных основаны на целочисленном типе данных.
Есть различные типы операций - арифметические, логические, сдвиг.
С точки зрения набора операций, если мы отказываемся от беззнакового типа данных, нам необходимо ввести 1 операцию.
SAL SAR
SHL SHR - SHR 2 операции
2. Логический тип
Он необходим, и во всех ЯП он есть
true false
boolean
bool
logical
Обычно, его делали как сужение integer
typedef unsigned int BOOL;
Ничего не стандартизовано, так что разные ЯП реализовывали его по-разному. В WinAPI есть GetMessage() он возвращает 3 значения: больше нуля, ноль , -1, который говорит об ошибке. В некоторых языках есть преобразование из bool в int и из int в bool.
Bool был введен для проверки типов на этапе компиляции в C++.
Аналогично enum - псевдотип данных. Совместимость со старым С - служит тормозом.
true false = логические операции принимают 0 и 1. А если они сравниваются с обычными числами, то работает приведение -1 в 1.
Соответствие операций
Обычные языки в арифметических операциях сходятся, но не равны
<>
!=
#
/=
while(A[i]#X) AND (i<=N) do inc(i) and;
Но здесь у нас нет квазистатической проверки, мы можем выйти out of range.
Сейчас идет стандарт, что логические операции выполняются слева направо, а другие, типа «+++» как угодно. Логические операции сейчас у нас ленивые, чтобы не было лишних вычислений.
3. Символьный тип данных.
Сейчас он тоже является базисным типом данных. Все символьные типы основаны на понятии character set. Фиксируем алфавит и набор управляющих (специальных) символов. Этот набор фиксируется в виде таблиц по 16 столбцов. Сверху символы, сбоку номер. Понятие charset оформилось еще тогда, когда появилась азбука Морзе. С точки зрения 50-х годов, например, американцам хватало 7 битов, ASCII-7.
Из-за того, что не всем хватало кодировок, пошли разные кодировки. Например, ANSI. Впервые, 8-битные кодировки появились в 60-х годах, с машинами IBM. Вся проблема была в том, чтобы язык попадал в старшую кодировку(см кодировку ANSI). Сначала почтовый сервер смотрел в первые 7 бит символа, 8 бит - контроль четности. Перевести компьютер на японский язык было очень тяжело.
Необходима была стандартизация. Кодировки ANSI, ISO, Ciryllic. Но все это были 8-битные кодировки. Проблема их в том, что Windows вплоть до XP использовали 8-битные, это приводило к тому, что в Notepad можно было набить русский и английский, французский и английский, но не английский, русский, французский, так как они находились в разных Code page. Изобрели ucs-2 и ucs-4. Unicode соответствует UCS-2. Сначала были проблемы в связи с тем, что система была написана на Unicode, а программы на 8-битной кодировке. В Unix был Motif. XmString - можно было работать с ним, поддерживались charset. С точки зрения универсальности это было очень хорошо. Во всех порядочных ЯП char поэтому и не совместим с целыми типами.
В таких языках, как Java C# char не переводится в int. В C++ w_char переводится в int (унаследовано от С)
i18n