Опубликован: 23.10.2009 | Уровень: для всех | Доступ: свободно
Лекция 5:

Типы данных

< Лекция 4 || Лекция 5: 12 || Лекция 6 >
Аннотация: В данной лекции Вы познакомитесь с основными типами "машинных данных" и допустимыми операциями над ними. Вы также узнаете разницу между "машинными" и "пользовательскими" типами данных.
Ключевые слова: тип данных, эффективная реализация, точность, visual, Basic, script, vbscript, программирование, Java, автор, приведение типов, unsigned, char, бит, binary digit, байт, гигабайт, распределенные базы данных, компьютер, центральный процессор, регистр, память, слово, здравый смысл, целочисленный тип, дополнительный код, short, NPB, инкремент, декремент, операции отношения, приоритет операций, остаток от деления, программное прерывание, divide-by-zero, 'overflow', дизъюнкция, исключающее ИЛИ, логическое программирование, унарные операции, XOR, битовые операции, ANSI, булевский тип, реализация языка, булевское выражение, логическая переменная, операции, мантисса, тип float, исчезновение порядка, системное программирование, процедурное программирование, subroutine, однозначность результата, микропроцессор, создание пользователя, объектно-ориентированное программирование, ООП, операция приведения, потеря информации, I-MPEG, сегментный регистр, регистр флагов, оператор условия, VBA, JScript, исключительная ситуация, логическое ИЛИ, кроссплатформенность, счисление

"Программа = Алгоритм + Структура данных"

Н. Вирт.

Цель лекции:

  1. Познакомиться с основными типами данных и научиться использовать их.
  2. Познакомиться с операциями над типами данных.
  3. Изучить особенности каждого типа данных.

Как уже указывалось в эпиграфе, в этой лекции будет подробно рассказано о типах данных - константах, переменных и т.п., используемых при программировании на любом языке. Правильно выбранный тип данных влияет не только на реализацию тех или иных алгоритмов - от него также зависит эффективность реализации алгоритма, скорость вычислений, размер программы, точность расчетов и т.п.

Следует отметить, что концепция типов данных не реализована в таких языках, как 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" - отрицательным числом.

Примечание: отрицательные числа представляют в ЭВМ в виде дополнительного кода. Подробнее о дополнительном коде смотри, например, [62], а также школьные учебники по информатике [35, 36, 53, 54].
Таблица 5.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
4 байта <идентификатор>% Существует только один целый тип
Java
1 байт byte со знаком b
2 байта short со знаком n
4 байта int со знаком i
8 байт long со знаком l
C/C++
1 байт char со знаком c
unsigned char без знака uc
2 байта short со знаком n
unsigned short без знака un
4 байта long со знаком l
unsigned long без знака ul
2 или 4 байта int со знаком i, n
unsigned без знака u
C/C++

Windows

API
2 или 4 байта BOOL int fb
1 байт BYTE unsigned char b
2 байт WORD unsigned short w
4 байта DWORD unsigned long dw
2 или 4 байта UINT unsigned int u
Указатели:
2 байта PSTR char near * npsz
2 байта NPSTR char near * npsz
4 байта LPSTR char far * lpch
4 байта LPCSTR const char far * lpsz
2 байта PBYTE BYTE near * npb
4 байта LPBYTE BYTE far * lpb
2 байта PINT int near *
4 байта LPINT int far *
2 байта PWORD WORD near * npw
4 байта LPWORD WORD far * lpw
2 байта PLONG long near *
4 байта LPLONG long far *
2 байта PDWORD DWORD near * npdw
4 байта LPDWORD DWORD far * lpdw
4 байта LPVOID void far * - дальний указатель на пустой тип lpv

В таблице 5.2 дается соответствие между разрядностями целочисленных регистров и связанными с ними обозначениями типов на языках Quick Basic, C/C++, Java. В этой же таблице приведены "псевдонимы" "машинных" типов данных, применяемых в библиотеке Windows API. Подробнее о Windows API смотри в книгах [86-91].

5.2.2. Целочисленная арифметика

С целочисленными типами данных возможны следующие операции:

  • сложение;
  • вычитание;
  • умножение;
  • целочисленное деление;
  • нахождение остатка от деления;
  • смена знака числа;
  • инкремент числа;
  • декремент числа;
  • а также все операции отношения.

Все эти операции, их обозначения, действия, а также приоритеты операций и комментарии к ним смотри таблицу 5.3.

Таблица 5.3. Арифметические операции
Название операции Обозначение Приоритет Кол-во операндов Примечание
Целочисленная арифметика
Сложение + 8 2
Вычитание - 8 2
Умножение * 7 2
Целочисленное деление / 7 2
Остаток от деления % 7 2
Смена знака числ - 5 1
Инкремент числа ++ 3 1
Декремент числа -- 3 1
Отношение "Больше" > 11 2
Отношение "Больше или равно" >= 11 2
Отношение "Меньше" < 11 2
Отношение "Меньше или равно" <= 11 2
Отношение "Равно" (Си под.) == 12 2
Отношение "Равно" (Basic) = 12 2
Отношение "Не равно (Си под.) != 12 2
Отношение "Не равно (Basic) <> 12 2
Арифметика плавающей точки
Сложение + 8 2
Вычитание - 8 2
Умножение * 7 2
Целочисленное деление / 7 2
Остаток от деления % 7 2
Смена знака числа - 5 1
Инкремент числа ++ 3 1
Декремент числа -- 3 1
Отношение "Больше" > 11 2
Отношение "Больше или равно" >= 11 2
Отношение "Меньше" < 11 2
Отношение "Меньше или равно" <= 11 2

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) только целочисленные значения. Для этих целей использование целочисленной арифметики - "естественно".

Примечание: В интерпретируемом языке Perl есть возможность "включения/выключения" целочисленной арифметики. Это делается при помощи директив:
  • use integer - для включения целочисленной арифметики;
  • no integer - для выключения целочисленной арифметики.

Подробнее смотри [59].

5.3. Булевы типы. Булева алгебра

5.3.1. Булева алгебра: введение

Булева алгебра - это раздел математики, изучающий операции с логическими данными, то есть данными, принимающие значения: "Истина" и "Ложь" (по-английски: "true" и "false"). Эта дисциплина была разработана английским математиком XIX века Джорджем Булем, имя которого она носит.

К булевым операциям (которые в русскоязычной литературе чаще называют логическими операциями) относятся:

  • конъюнкция (логическое "И");
  • дизъюнкция (логическое "ИЛИ");
  • отрицание (логическое "НЕ");
  • логическое "исключающее ИЛИ";
  • логическая "эквивалентность";
  • логическое "следствие".

Из этих логических операций первые три операции присутствуют практически во всех языках программирования, а последние две - только в языках логического программирования (и то не во всех). При этом операция логического "НЕ" - унарная операция, применимая к следующей за ней переменной, а остальные операции - бинарные (применимые к паре значений: предыдущему и последующему). Результаты логических операций представлены [в таблице 5.4]. В ней же представлены обозначения этих операций в математике, языках Quick Basic, C/C++, Java.

Таблица 5.4. Операции Булевой алгебры
Название операции Обозначение Приоритет Кол-во операндов Примечание
Логическое "И" (Си) && 15 2
Логическое "И" (Basic) AND 15 2
Логическое "ИЛИ" (Си) || 16 2
Логическое "ИЛИ" (Basic) OR 16 2
Логическое "НЕ" (Си) ! 12 1
Логическое "Не" (Basic) NOT 12 1
Битовое "И" & 13 2
Битовое "ИЛИ" | 14 2
Битовое "Исключающее ИЛИ" (XOR) ^ 14 2
Примечание: битовые операции реализуют операции побитно, например 2 & 1 выдаст 0 (10 & 01 = 00)

Результаты логических операций:
Конъюнкция A && B A = TRUE A = FALSE
B = TRUE TRUE FALSE
B = FALSE FALSE FALSE
Дизъюнкция A || B A = TRUE A = FALSE
B = TRUE TRUE TRUE
B = FALSE TRUE FALSE
Исключающее ИЛИ А ^ B A = TRUE A = FALSE
B = TRUE FALSE TRUE
B = FALSE TRUE FALSE
Эквивалентность А <=> B A = TRUE A = FALSE
B = TRUE TRUE FALSE
B = FALSE FALSE TRUE

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 и его "клонах".

Примечание: при вычислении булевских выражений часто не требуется принудительно приводить значения логических выражений логической переменной.
< Лекция 4 || Лекция 5: 12 || Лекция 6 >