Под понятием "Тип данных" скрывается семантическое свойство информации. Для компьютера, все байты информации представляют собой пакеты из 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.
Целое число является основным типом целых чисел для машин с 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 точек. Да ещё и они могут быть цветные, и таким образом потребуется непомерное количество байтов для хранения всех возможных изображений литер и их цветов. И это ещё не говоря о всяких графических пиктограммах (смайлики, флажки, стрелки, дома и т.д.). Поэтому в своё время был предложен компромиссный вариант для хранения литер. Суть идеи состояла в том, что печатной (служебной) литере должен соответствовать свой код-число. А уж если потребуется, потом можно добавить различные способы вывода кода этой литеры на экран, принтер, плоттер и т.д. Тогда хранение литеры в памяти компьютера становится компактным и универсальным.
Эти литеры занимают в памяти ПК всего 1 байт. Если речь идёт исключительно о латинском алфавите (22 буквы), то им вполне можно пользоваться. Но вот проблема: если будет желание выводить символы на национальном алфавите, вместо ожидаемого результата будет непонятно что. А суть этой проблемы в том, что этот набор литер принимался как стандарт на заре компьютерной эпохи. Мало кто задумывался об этой проблеме, поэтому литеры набора Latin-1 даны скорее для обратной совместимости со старыми программами, чем для реального использования. Переменные такого типа описываются ключевым словом SHORTREAL:
Этот набор литер по сравнению с предыдущим является более прогрессивным. Он лишён недостатков 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 -- результат будет вещественное число. КП прекрасно понимает, что без этого результат очень неточным. Поэтому, если результат такого деления попытаться присвоить целочисленной переменной -- такой модуль даже не удастся скомпилировать -- Компонентный Паскаль просто не позволит это сделать! В то же время, если сумма двух целых превышает динамический диапазон целого -- КП на стадии компиляции постарается выяснить этот факт, и потребует результат присваивать длинному целому. Если выяснить на этапе компиляции это невозможно, КП во время исполнения остановит программу, и не позволит проскочить момент переполнения и "улететь программе в космос".
Те же самые правила касаются и остальных преобразований типов. Коротко схему преобразования типов можно отобразить так:
То, что выше было написано про числовые типы, применимо и к литеральным типам. Также надо учитывать, что приведение SHORTCHAR к CHAR будет затруднено, так как КП просто не будет знать, какая была национальная кодировка типа SHORTCHAR.
Коротко схему преобразования типов можно отобразить так:
В этом разделе будет приведён пример, показывающий как использовать переменные различных типов. Прежде чем будет приведён полный текст программы, кое-какие пояснения:
Описание переменных всегда в КП выносится в отдельную секцию модуля, которая обозначается ключевым словом VAR (variable, переменная).
Описание констант всегда в КП выносится в отдельную секцию модуля, которая обозначается ключевым словом CONST (constante, постоянная/неизменяемая).
Hello02.odc
Текст программы и результат её обработки и выполнения.
MODULETestHello02;(* это вторая программа на языке Компонентный Паскаль. Она выполняет кое-какие математические операции *)IMPORTKernel,Log,Math;CONSTc=2;VARi:INTEGER;i1:REAL;PROCEDUREStart*;VARBEGINi:=3;i1:=c/i;Log.String('Результат программы: ');Log.Real(i1);Log.LnENDStart;BEGINENDTestHello02.
Необходимо обратить внимание, что константе "с" не нужно присваивать значение, а её тип (судя по всему) компилятор определил, как INTEGER. Наоборот, переменной "i" необходимо присвоить значение, так как при запуске программы, в ней находится "мусор" -- случайные значения, оставшиеся от работы предыдущей программы (которая пользовалась этим участком памяти). Переменной "i1" также не нужно присваивать начальное значение, так как нам оно -- не интересно. Переменная "i1" получает своё значение в результате вычислений.
Если всё сделано правильно, то можно будет увидеть результат, примерно такой, как на скриншоте справа. Удивляемся размеру программы (88 байт), убеждаемся, что деление двух целых чисел привело к результату REAL, вспоминаем как вставить КОММАНДЕР и использовать его.
Здесь могут возникнуть вопросы, поэтому ниже приводятся необходимые пояснения:
В первом случае, при присвоении константе "с" значения "3" -- стоит знак равно. И это правильная математическая форма записи.
Во втором случае, переменная "i1" содержит "мусор", который никак не может быть равен "с/i", и чтобы подчеркнуть этот факт, что это не математическое уравнение, а инструкция присваивания в КП принято в инструкциях использовать символ ":=", как не нарушающий математические соглашения.
В ряде языков (в том числе, таком популярном, как Си) знак равно используется и для сравнения чисел в условиях, и это очень часто является источником ошибок. В Компонентном Паскале такие ситуации исключены. Ведь этот язык (в том числе) и для промышленного программирования.
↑Вообще, существуют компьютеры, которые контролируют типы данных на этапе исполнения программы и обработки данных. Например, см. "Эльбрус-3М1, ОС Эльбрус"
↑Из-за того, что тип переменных не меняется -- Компонентный Паскаль и является языком со статической типизацией. А такой язык, как python позволяет менять типы переменных, поэтому он относится к языкам программирования с динамической типизацией.