Компонентный Паскаль/Переменные и константы
Типы данных
правитьПод понятием "Тип данных" скрывается семантическое свойство информации. Для компьютера, все байты информации представляют собой пакеты из 8 бит. Каждый из битов может быть включенным или выключенным. В зависимости от того, как принято понимать эти состояния (прямая или инверсная логика) -- эти значения принимаются равными "0" или "1". Больше о содержимом ячеек памяти компьютер не знает ничего.
Но для программиста даже один байт может содержать различные типы информации. Например, 8 бит (= 1 байт), с точки зрения программиста -- может содержать числа от 0 до 255. А может и код символа в в однобайтовой кодировке ("а", "б", "в"...). А может и вообще что-то иное. Но все байты одинаковы, у них нет признака того, что они хранят[1]. В какой-то момент, программист вполне может решить, что вот эта ячейка памяти хранит число от 0 до 255. А на самом деле, в самом начале, программист задумывал хранить в этой ячейке памяти код символа для последующей печати. Более того, вполне может быть, что программист решил использовать под свои нужды не одну, а сразу две (или даже тысячу) ячеек? Помнить где расположена каждая ячейка? И такие ошибки встречаются и у новичков, и у опытных программистов. Как решить эту проблему?
Проблема решается тем, что помнить о том, где расположена каждая ячейка памяти, и что она хранит -- должен Компонентный Паскаль. Этой информации нет в самой ячейке, зато есть у языка программирования. Это и есть семантическое свойство информации, в данном случае -- её тип. Таким образом описанная ячейка называется переменная. Свой тип она не меняет с момента её описания, до момента окончания выполнения программы. Исключений не бывает. [2]
Целые числа
правитьЛогический тип
правитьЛогический тип, в полном смысле этого слова не является целым. Но и к дробным числам этот тип можно отнести ещё меньше. Переменная такого типа может принимать только два значения. В Компонентном Паскале эти два значения определены как TRUE ("Истина") и FALSE("ложь"). Этот тип переменных используется даже шире, чем об этом задумываются многие программисты. Логический тип можно использовать явно (через переменную), а можно и неявно (например, через сравнение двух чисел, строк, результатов вызовов процедур). Обозначается такой тип через ключевое слово BOOLEAN. Пример:
flagZ : BOOLEAN; (* флаг признака нуля *)
sep0 : BOOLEAN; (* сепаратор; отвечает за разделение глав *)
Стоит обратить внимание на выравнивание двоеточий и ключевых слов. Двоеточие, если проводить аналогию с русским языком может выступать как указатель на обстоятельство, как во фразе: "Итак: всё плохо!". Только в случае с КП этот разделитель служит для указания типа (справа) для переменной (что слева).
Байтовый тип
правитьИли просто байт. Обозначается ключевым словом BYTE. Переменная такого типа может принимать значения от 0 до 255. Это совсем не много, но для многих целей может оказаться вполне достаточно. Например, не существует минут и секунд более 60. Или например не бывает дня в месяце с номером 32. Пример описания переменной типа BYTE:
day : BYTE;
level : BYTE;
Важно не забывать ставить точку с запятой после всех определений переменных (после определения последней переменной точку с запятой можно не ставить). Кроме того, следует помнить, что особенности современных компьютеров: они не работают с одним байтом, они работают, скажем, сразу с 4-мя байтами. Поэтому возможны такие эффекты, как неэкономное расходование памяти. Как избежать таких эффектов будет рассмотрено в дальнейших частях.
Короткое целое
правитьКороткое целое число в БлэкБоксе/КП определено как 2 байта. В последней редакции сказано, что размеры типов не зависят от аппаратной платформы, но в текущей реализации КП, которая была скомпилирована под архитектуру 32 бита, короткое целое именно 2 байта. Диапазон чисел, которые умещаются в эти 2 байта составляет примерно от -32000 до +32000. Короткое целое обозначается ключевым словом SHORTINT.
Пример объявления коротких целых:
count_pak : SHORTINT; (*счётчик пачек *)
all_palet : SHORTINT; (*всего паллет*)
Как видно, в целом, определение переменных базовых типов однообразно и их легко запомнить.
Целое
правитьЦелое число является основным типом целых чисел для машин с 32 битами на машинное слово. Для КП это именно тот случай. Целое число занимает в памяти 4 байта. Такого количества памяти хватает на описание числа примерно от -2,1 млрд. до +2,1 млрд. Не часто встречаются числа с таким динамическим размахом. Целый тип описывается ключевым словом INTEGER:
count1 : INTEGER;
count2 : INTEGER;
И здесь ничего нет такого, чтобы потребовало особого способа описания переменных.
Длинное целое
правитьСамый широкий диапазон целых чисел, который встроен в КП. Занимает 8 байт, представляет целые числа в диапазоне примерно от -9,2*10^18 до 9,2*10^18. Даже сложно представить, где такие числа вообще могут потребоваться обычным людям. Обозначаются такие переменные как LONGINT:
dist_solar : LONGINT; (* расстояние до Солнца *)
dist_pluton : LONGINT; (* расстояние до Плутона *)
Следует помнить, что сборка BlackBox Red (впрочем, как и другие) оптимизированы под 32-х битную архитектуру, поэтому работа с такими числами будет существенно медленней, чем с типом INTEGER.
Вещественные числа
правитьВещественные (дробные, рациональные) числа называются так потому, что в окружающем мире редко встречаются "целые" объекты. Например, слоны. Они вроде все слоны. Но слонёнок по массе -- это целый слон? Если нет, то как отразить его массу через целого слона? Кроме того, очень часто приемлемо записывать числа с заданной точностью. Они для этого подходят как никто. Таким образом, вещественные числа находят более чем широкое применение в промышленности.
Короткое вещественное
правитьТакие числа соответствуют вещественным числам в языке Си. В памяти они занимают 4 байта, но в отличии от целых чисел они имеют особый формат при хранении. Это приводит к тому, что точность таких чисел ограничивается 7-8 десятичных цифр. На зато диапазон этих чисел раздвигается до -3,4*10^(38)...-10^(-38) в отрицательной области, и до 10^(-38)...3,4*10^(38) в области положительных чисел. Даже по сравнению с типом LONGINT это очень много. Но есть и обратная сторона медали. Если в типе LONGINT точность до последнего знака, то в данном случае (как уже было выше упомянуто) только до 7-8. Поэтому, если в вычислениях важна точность, надо помнить о том, что точность больших чисел огрубляет точность малых чисел. Это правило определяет порядок работы с вещественными числами: "сначала маленькие, потом большие" при увеличении, и "сначала большие, потом маленькие" при уменьшении. Такие числа обозначаются ключевым словом SHORTREAL:
mas_zil : SHORTREAL; (* масса автомобиля ЗиЛ *)
mas_kamaz : SHORTREAL; (* масса автомобиля КамАЗ *)
Отдельно стоит упомянуть то, что вещественные числа обрабатываются на математическом сопроцессоре, и обычно, работа с вещественными числами происходит медленней, чем с целыми.
Вещественное число
правитьЭтот тип чисел занимает в памяти в 2 раза ячеек больше, чем короткое вещественное -- 8 байт и соответствует числу с двойной точностью стандарта "IEEE 754". Диапазон, который охватывают такие числа, если записывать от руки без научного формата -- утомит очень быстро (примерно -10^308...10^308). Точность составляет 15-17 десятичных знаков. Если через метры записывать диаметры ядер атомов -- такой точности как раз должно хватить[3]. Переменная вещественного типа описывается ключевым словом REAL:
mas_andro : REAL; (* масса галактики Андромеды *)
mas_galac : REAL; (* масса нашей галактики *)
Литерные типы
правитьЛитерными типами называют такие типы данных, которые имеют какое-либо отношение к отображению. Например, буквы, строки, тексты, цифры, управляющие символы (перевод строки, новая строка, гудок и т.д.). Дело в том, что такие символы крайне важны для человека (и к ним совершенно равнодушен компьютер). Но на экране, принтере, плоттере -- любой из этих символов состоит из множества точек (матрицы). И такая матрица может достигать размера 1200х2400 точек. Да ещё и они могут быть цветные, и таким образом потребуется непомерное количество байтов для хранения всех возможных изображений литер и их цветов. И это ещё не говоря о всяких графических пиктограммах (смайлики, флажки, стрелки, дома и т.д.). Поэтому в своё время был предложен компромиссный вариант для хранения литер. Суть идеи состояла в том, что печатной (служебной) литере должен соответствовать свой код-число. А уж если потребуется, потом можно добавить различные способы вывода кода этой литеры на экран, принтер, плоттер и т.д. Тогда хранение литеры в памяти компьютера становится компактным и универсальным.
Литеры набора Latin-1
правитьЭти литеры занимают в памяти ПК всего 1 байт. Если речь идёт исключительно о латинском алфавите (22 буквы), то им вполне можно пользоваться. Но вот проблема: если будет желание выводить символы на национальном алфавите, вместо ожидаемого результата будет непонятно что. А суть этой проблемы в том, что этот набор литер принимался как стандарт на заре компьютерной эпохи. Мало кто задумывался об этой проблеме, поэтому литеры набора Latin-1 даны скорее для обратной совместимости со старыми программами, чем для реального использования. Переменные такого типа описываются ключевым словом SHORTREAL:
lit_a : SHORTCHAR; (* латинская литера "а" *)
lit_b : SHORTCHAR; (* латинская литера "б" *)
Стоит добавить, что кроме букв и цифр в литерах Latin-1 есть ещё и разные интересные значки, которые, иногда, могут и пригодиться [4].
Литеры набора Unicode
правитьЭтот набор литер по сравнению с предыдущим является более прогрессивным. Он лишён недостатков Latin-1, но у каждой медали две стороны. Да, теперь в этот набор Unicode помещаются литеры всех языков мира существующих, или когда-либо существовавших. Туда же помещаются различного рода пиктограммы из всех сфер жизни (значки Солнца, Луны, Земли и даже "Серп и молот"). Но, если байтовые литералы было легко сравнивать, так как они располагались в алфавитном порядке, то как понять, какой код меньше и на каком основании: английский литерал "а" или русский литерал "а"? А это совершенно разные литералы. К счастью, все (или почти все) процедуры для работы с литералами Unicode написаны, и сомнительно, что программисту придётся писать что-то своё (с высокой степенью вероятности это будет велосипед, как говорят программисты). Такой тип переменных описывается ключевым словом CHAR:
lit_a_en : CHAR; (* английская литера "a" *)
lit_a_ru : CHAR; (* русская литера "а" *)
Ещё раз стоит обратить внимание -- в данном примере (в наборе Unicode) русские и английские литеры кодируются различными кодами, хотя внешне и выглядят одинаково[5].
Константы
правитьКонстантой называется такая переменная, которую нельзя изменять в ходе выполнения программы. Преимущества констант перед переменными можно выразить следующими положениями:
- Тип констант определяется автоматически. Т.е. программисту не нужно думать при описании константы о том, какой тип данных должен наилучшим образом соответствовать именно этой константе.
- Преимущество констант перед переменными также в том, что если программист забудется, и попытается работать с константой, как с переменной -- компилятор КП настойчиво напомнит программисту о том, что он сам запретил менять константу. И это приведёт к избежанию ошибок разработки и исполнения.
- Также константы заметно быстрее обрабатываются компьютером, чем переменные.
Форма их определения существенно отличается от формы определения переменных:
fail = 1;
eee = 2;
good = 3;
wery_good = 4;
wou = 5;
Форма описания констант определена не через двоеточие, а через знак "равно". И в данном случае это вполне соответствует законам логики и математики. Также стоит обратить внимание, что константа "wery_good" и её знак "равно" не выровнены со всеми константами. Это допущение вполне приемлемо при оформлении кода. Ну что делать, если имя переменной, такое длинное?
Преобразования типов
правитьЯзык Компонентный Паскаль был спроектирован, а не сочинён. Поэтому правила преобразования типов просты, понятны и предсказуемы.
Преобразования числовых типов
правитьКак уже было выше описано, самым мощным диапазоном представления чисел является тип REAL. В случае преобразований при необходимости, этот тип преобразуется в более ограниченный -- SHORTREAL. Если этот тип придётся преобразовывать, он в свою очередь сужается до LONGINT. Тип длинное целое при сжатии переходит в тип INT (4 байта). После типа целого сжатие диапазона идёт в сторону SHORTINT (2 байта). Короткое целое тоже может быть сжато до BYTE. Дальше диапазон числа уменьшить нельзя. Тип BOOLEAN, строго говоря числовым не является, хотя и содержит логические "0" и "1". Обратное преобразование также верно. Например, если разделить два целых числа 3 и 2 -- результат будет вещественное число. КП прекрасно понимает, что без этого результат очень неточным. Поэтому, если результат такого деления попытаться присвоить целочисленной переменной -- такой модуль даже не удастся скомпилировать -- Компонентный Паскаль просто не позволит это сделать! В то же время, если сумма двух целых превышает динамический диапазон целого -- КП на стадии компиляции постарается выяснить этот факт, и потребует результат присваивать длинному целому. Если выяснить на этапе компиляции это невозможно, КП во время исполнения остановит программу, и не позволит проскочить момент переполнения и "улететь программе в космос". Те же самые правила касаются и остальных преобразований типов. Коротко схему преобразования типов можно отобразить так:
REAL >= SHORTREAL >= LONGINT >= INTEGER >= SHORTINT >= BYTE
Преобразования литеральных типов
правитьТо, что выше было написано про числовые типы, применимо и к литеральным типам. Также надо учитывать, что приведение SHORTCHAR к CHAR будет затруднено, так как КП просто не будет знать, какая была национальная кодировка типа SHORTCHAR. Коротко схему преобразования типов можно отобразить так:
CHAR >= SHORTCHAR
Использование переменных и констант
правитьВ этом разделе будет приведён пример, показывающий как использовать переменные различных типов. Прежде чем будет приведён полный текст программы, кое-какие пояснения:
- Описание переменных всегда в КП выносится в отдельную секцию модуля, которая обозначается ключевым словом VAR (variable, переменная).
- Описание констант всегда в КП выносится в отдельную секцию модуля, которая обозначается ключевым словом CONST (constante, постоянная/неизменяемая).
Hello02.odc
MODULE TestHello02;
(* это вторая программа на языке
Компонентный Паскаль. Она выполняет
кое-какие математические операции *)
IMPORT Kernel, Log, Math;
CONST
c = 2;
VAR
i: INTEGER;
i1: REAL;
PROCEDURE Start*;
VAR
BEGIN
i := 3;
i1 := c / i;
Log.String('Результат программы: ');
Log.Real(i1);
Log.Ln
END Start;
BEGIN
END TestHello02.
Необходимо обратить внимание, что константе "с" не нужно присваивать значение, а её тип (судя по всему) компилятор определил, как INTEGER. Наоборот, переменной "i" необходимо присвоить значение, так как при запуске программы, в ней находится "мусор" -- случайные значения, оставшиеся от работы предыдущей программы (которая пользовалась этим участком памяти). Переменной "i1" также не нужно присваивать начальное значение, так как нам оно -- не интересно. Переменная "i1" получает своё значение в результате вычислений.
Если всё сделано правильно, то можно будет увидеть результат, примерно такой, как на скриншоте справа. Удивляемся размеру программы (88 байт), убеждаемся, что деление двух целых чисел привело к результату REAL, вспоминаем как вставить КОММАНДЕР и использовать его.
Немного о присваивании
правитьВ коде представленном выше используется знак равно в двух вариантах:
CONST
с = 2;
.............<scip>...............
i := 3;
i1 := c/i;
Здесь могут возникнуть вопросы, поэтому ниже приводятся необходимые пояснения:
- В первом случае, при присвоении константе "с" значения "3" -- стоит знак равно. И это правильная математическая форма записи.
- Во втором случае, переменная "i1" содержит "мусор", который никак не может быть равен "с/i", и чтобы подчеркнуть этот факт, что это не математическое уравнение, а инструкция присваивания в КП принято в инструкциях использовать символ ":=", как не нарушающий математические соглашения.
- В ряде языков (в том числе, таком популярном, как Си) знак равно используется и для сравнения чисел в условиях, и это очень часто является источником ошибок. В Компонентном Паскале такие ситуации исключены. Ведь этот язык (в том числе) и для промышленного программирования.
Примечания
править- ↑ Вообще, существуют компьютеры, которые контролируют типы данных на этапе исполнения программы и обработки данных. Например, см. "Эльбрус-3М1, ОС Эльбрус"
- ↑ Из-за того, что тип переменных не меняется -- Компонентный Паскаль и является языком со статической типизацией. А такой язык, как python позволяет менять типы переменных, поэтому он относится к языкам программирования с динамической типизацией.
- ↑ По форматам вещественных чисел стоит посмотреть материал отдельно: Число_одинарной_точности, Число_двойной_точности
- ↑ Также набор символов Latin-1 известен как ISO_8859-1, первая часть этой таблицы -- ASCII
- ↑ Кодировка Unicode (Юникод) весьма сложна, убедиться в этом можно прочитав статью про Юникод
.