Типы данных
"Программа = Алгоритм + Структура данных"
Цель лекции:
- Познакомиться с основными типами данных и научиться использовать их.
- Познакомиться с операциями над типами данных.
- Изучить особенности каждого типа данных.
Как уже указывалось в эпиграфе, в этой лекции будет подробно рассказано о типах данных - константах, переменных и т.п., используемых при программировании на любом языке. Правильно выбранный тип данных влияет не только на реализацию тех или иных алгоритмов - от него также зависит эффективность реализации алгоритма, скорость вычислений, размер программы, точность расчетов и т.п.
Следует отметить, что концепция типов данных не реализована в таких языках, как Perl, Visual Basic Script (VBScript), не полностью реализована в Quick Basic, Visual Basic и т.п. Именно поэтому не рекомендуется использовать эти языки для начинающих изучать программирование.
Типы данных в таких языках, как C, C++, Java можно принудительно приводить к определенному типу. В этих языках автор советует так и поступать - если потребуется, применять принудительное приведение типов, а не ограничиваться приведением по-умолчанию. В противном случае могут возникнуть ошибки, например: "Не могу привести тип 'unsigned char *' в 'const char *'".
5.1. Примитивные (машинные) типы данных
Как уже говорилось выше, почти во всех языках программирования выделяются "машинные" типы данных. Вкратце объясним их происхождение.
Как известно из школьных учебников по информатике [36, 54, 53, 35], любое число, любые символы, любые объекты в памяти ЭВМ представляются в виде последовательности нулей и единиц - битов. Бит (от английского Binary digIT) является единицей информации, принимающей одно из двух значений: "0" и "1". Поскольку бит - очень малая величина, информацию обычно выражают в байтах или кратных ему числе битов. Один байт соответствует восьми битам. Иначе говоря, в одном байте можно закодировать 256 (2^8) символов, представить целые числа без знака от 0 до 255, или представить целые числа со знаком от -128 до +127. Заметим, что все символы в компьютере представлены в виде целых чисел без знака.
Отступление. В середине 70-х годов XX века ученые подсчитали, что человеческий мозг вмещает в себя ~10^18 бит информации. Это число соответствовало в то время всей информации, содержащейся в библиотеке им. В.И. Ленина. В переводе на современный компьютерный язык это соответствует приблизительно одному экзабайту - миллиону гигабайт информации, что приближенно равно объему одной крупной распределенной базы данных бронирования авиабилетов и авиаперевозок (по оценкам автора). Почему же возможности мозга человека превышают возможности "компьютерного" интеллекта? Дело в том, что человеческий мозг может удерживать в своей памяти, по аналогии с кошельком, как "медные монеты" - необработанные записи, последовательности букв и цифр, так и "золотые монеты" - сложные, обработанные данные, в виде готовых концепций, теорем и т.д. Это делает мозг более "гибкой" системой, чем компьютер (позволяя, путем "сжатия с потерями" уменьшать объем информации в 100 и более раз).
Итак, все данные в ЭВМ представляются в виде одного или нескольких битов. Тогда напрашивается вопрос: "А откуда в языках программирования такое большое число машинных типов данных, если все кодируется битами?" Автор отвечает: количество машинных типов данных определяется количеством регистров и их типом в центральном процессоре ЭВМ. Регистр можно представить как "сверхоперативную", быструю, встроенную в центральный процессор память. Эти регистры имеют длину 1 байт, 2 байта ("полуслово", "слово"), 4 байта ("слово", "двойное слово") и 8 байт ("двойное слово"). Изредка используются и более длинные регистры (например, для хранения [чисел с плавающей точкой] повышенной разрядности).
Помимо своего размера (так называемой разрядности) регистров различают также назначение регистра и формат хранимых в нем данных. Подробнее о машинных типах данных смотри этот раздел ниже.
5.2. Целые числа и целочисленная арифметика
5.2.1. Целый тип
Наиболее простыми в реализации и "очевидными" с точки зрения "здравого смысла" являются целочисленные типы данных. Они представляют собой запись чисел в "двоичном" формате, в виде последовательности нулей и единиц. Различают два вида целых чисел: "целые без знака" и "целые со знаком".
Тип данных "целые без знака" представляют собой натуральный ряд чисел, которые начинаются с "0" (а не с "1", как в математике!) и продолжаются вплоть до исчерпания разрядности регистра.
Тип данных "целые со знаком" содержат в старшем бите (по-другому - в самом "левом", первом по порядку бите) признак знака. Если этот бит имеет значение: "0", то число считается положительным, если "1" - отрицательным числом.
Тип регистра | min | max |
---|---|---|
целые без знака | ||
1 байт | 0 | 255 |
2 байта | 0 | 65 535 |
4 байта | 0 | 4 294 967 295 |
8 байт | 0 | 18 446 744 073 709 600 000 |
целые со знаком | ||
1 байт | -128 | 127 |
2 байта | -32 768 | 32 767 |
4 байта | -2 147 483 648 | 2 147 483 647 |
8 байт | -9 223 372 036 854 780 000 | 9 223 372 036 854 780 000 |
В таблице 5.1 представлены максимальное (max) и минимальное (min) значения, применяемые числами в целочисленных регистрах различной разрядности для типов "целые со знаком" и "целые без знака". Между этими максимальными и минимальными значениями могут принимать целочисленные значения константы и переменные указанных типов.
В таблице 5.2 дается соответствие между разрядностями целочисленных регистров и связанными с ними обозначениями типов на языках Quick Basic, C/C++, Java. В этой же таблице приведены "псевдонимы" "машинных" типов данных, применяемых в библиотеке Windows API. Подробнее о Windows API смотри в книгах [86-91].
5.2.2. Целочисленная арифметика
С целочисленными типами данных возможны следующие операции:
- сложение;
- вычитание;
- умножение;
- целочисленное деление;
- нахождение остатка от деления;
- смена знака числа;
- инкремент числа;
- декремент числа;
- а также все операции отношения.
Все эти операции, их обозначения, действия, а также приоритеты операций и комментарии к ним смотри таблицу 5.3.
5.2.3. Особые ситуации при работе с целыми числами
Целочисленная арифметика генерирует следующие ошибки [39,40], вызывает так называемые программные прерывания:
- деление на ноль (divide by zero);
- переполнение (overflow) - попытка записать в регистр целое число с разрядностью, превышающей разрядность регистра, например: short i = 2000000 или unsigned short u=-1;
- исчезновение знака - прерывание, указывающее, что в старший бит регистра (то есть в признак знака) был перенос единицы из следующего за ним разряда (бита). Соответствует прерыванию "переполнение", но для целых чисел со знаком.
5.2.4. Замечания о целочисленном делении
Замечание по целочисленному делению. Целочисленное деление отличается от "обычного математического" деления в том, что при целочисленном делении происходит "отбрасывание" дробной части результата, например:
- 2/3 = 0;
- 3/3 = 1;
- 4/3 = 1;
- 5/3 = 1;
- 6/3 = 2;
- и т.д.
На практике это приводит к большим ошибкам округления при расчетах. Но иногда следует использовать только целочисленную арифметику. Например, при выдаче информации на экран дисплея в "графическом" виде по-умолчанию используется (во всяком случае, в библиотеке Windows API) только целочисленные значения. Для этих целей использование целочисленной арифметики - "естественно".
- use integer - для включения целочисленной арифметики;
- no integer - для выключения целочисленной арифметики.
Подробнее смотри [59].
5.3. Булевы типы. Булева алгебра
5.3.1. Булева алгебра: введение
Булева алгебра - это раздел математики, изучающий операции с логическими данными, то есть данными, принимающие значения: "Истина" и "Ложь" (по-английски: "true" и "false"). Эта дисциплина была разработана английским математиком XIX века Джорджем Булем, имя которого она носит.
К булевым операциям (которые в русскоязычной литературе чаще называют логическими операциями) относятся:
- конъюнкция (логическое "И");
- дизъюнкция (логическое "ИЛИ");
- отрицание (логическое "НЕ");
- логическое "исключающее ИЛИ";
- логическая "эквивалентность";
- логическое "следствие".
Из этих логических операций первые три операции присутствуют практически во всех языках программирования, а последние две - только в языках логического программирования (и то не во всех). При этом операция логического "НЕ" - унарная операция, применимая к следующей за ней переменной, а остальные операции - бинарные (применимые к паре значений: предыдущему и последующему). Результаты логических операций представлены [в таблице 5.4]. В ней же представлены обозначения этих операций в математике, языках Quick Basic, C/C++, Java.
Конъюнкция A && B | A = TRUE | A = FALSE |
---|---|---|
B = TRUE | TRUE | FALSE |
B = FALSE | FALSE | FALSE |
5.3.2. Булевы типы
Как уже сказано выше, логические выражения могут принимать только два значения: "false" (ложь) и "true" (истина). Эти значения-константы определены следующим образом:
- false = 0;
- true = 1, или true != 0.
Логично использовать для этих констант целое число разрядностью 1 бит, но... Поскольку минимальным размером регистра, отводимого под целое число, является 1 байт, то именно ячейка памяти этого размера служит для хранения числа с типом данных: "Boolean". На самом деле размер этого типа данных может составлять 2 или даже 4 байта. Это связано со следующими обстоятельствами.
В основном стандарте для языка Си: ANSI C, - отсутствует булевский тип данных. Вместо него используется целый тип данных: integer (int). Этот тип данных реализован в различных компиляторах по-разному, и занимает от 2-х до 4-х байтов. Константе "ложь" ("FALSE") соответствует значение; "0", а любое ненулевое значение воспринимается как "истина". Это позволяет написать на языке Си компактный код, например:
while( !eof( stream ) )
Описывает цикл "Пока", завершающийся при достижении конца файла, связанного с потоком stream. Информацию по потокам и окончанию файлов смотрите в следующих лекциях.
Не смотря на несоответствие стандарту ANSI C, в стандартной библиотеке Windows API для языков Си/Си плюс-плюс введен тип BOOL, являющегося реализацией булевского типа данных. Тип данных: "Boolean" также введен в стандартах на C++ и Java.
Булевский тип данных отсутствует в Quick Basic и более старых реализациях языка Basic, но присутствует в языке Visual Basic и его "клонах".