Модульные типы
Все целочисленные типы, которые мы рассматривали ранее, известны как целые числа со знаком. Для таких типов соблюдается правило - если в случае вычисления результат выходит за диапазон допустимых значений типа, то генерируется ошибка переполнения. Такие целочисленные типы были представлены стандартом Ada83.
Стандарт Ada95 разделяет целочисленные типы на целые числа со знаком и модульные типы. По существу, модульные типы являются целыми числами без знака. Характерной особенностью таких типов является свойство цикличности арифметических операций. Таким образом, модульные типы соответствуют целочисленным беззнаковым типам в других языках программирования (например: Byte, Word... - в реализациях Паскаля; unsigned_short, unsigned... - в C/C++).
В качестве простого примера рассмотрим следующий фрагмент кода:
. . . type Byte is mod 2 ** 8; -- (2 ** 8) = 256 Count : Byte := 255; begin
Count := Count + 1; . . . |
Здесь не производится генерация ошибки в результате выполнения сложения. Вместо этого, переменная Count, после выполнения сложения, будет содержать 0.
Кроме этого, с модульными типами удобно использовать знаки битовых операций "and", "or", "xor" и "not". Такие операции трактуют значения модульного типа как битовый шаблон. Например:
type Byte is mod 2 ** 8; -- (2 ** 8) = 256 Some_Var_1 : Byte; Some_Var_2 : Byte; Mask : constant := 16#0F# begin
. . . Some_Var_2 := Some_Var_1 and Mask; . . . |
Поскольку модульные типы не имеют отрицательных значений, для них допускается смешивание знаков битовых операций со знаками арифметических операций в одном выражении.
Следует заметить, что хотя при описании модульных типов зачастую используют степень двойки, использование двоичной системы счисления при описании модульных типов не является обязательным требованием.
Ада допускает выполнение преобразований беззнаковых чисел модульных типов в числа со знаком и обратно. При этом, производится проверка результата преобразования на допустимость диапазону значений типа назначения. В случае неудачи будет сгенерировано исключение Constraint_Error. Например:
type Unsigned_Byte is mod 2 ** 8; -- (2 ** 8) = 256 type Signed_Byte is range -128 .. +127;
U : Unsigned_Byte := 150; S : Signed_Byte := Signed_Byte(U); -- здесь будет сгенерировано исключение -- Constraint_Error |
Этот код будет вызывать генерацию исключения Constraint_Error.
В следующем параграфе приводятся описания предопределенных модульных типов представленных в пакете Interfaces. Заметим, что для этих модульных типов (они описаны с использованием двоичной системы счисления) предопределены операции побитного сдвига и вращения.