
- •СПбГУТ им. проф. М.А. Бонч-Бруевича Кафедра программной инженерии и вычислительной техники (ПИ и
- •Введение
- •Введение
- •Для чего нужны типы?
- •Для чего нужны типы?
- •1. Тип данных (тип)
- •Тип данных (тип)
- •Тип данных (тип)
- •Базовые типы данных языка Си
- •Пример: вещественные типы данных
- •Вещественные типы данных
- •2. Переменные и константы. Структура памяти в компьютере
- •Переменные и константы
- •Переменные и константы
- •Переменные и константы
- •Переменные и константы
- •3. Преобразование типов
- •4. Составные типы и указатели
- •Указатели
- •Оператор создания типов данных в Си
- •Резюме по языку Си
- •«Чудеса» Си. И как с этим жить
- •Небольшой список из популярных языков программирования
- •Выводы
Резюме по языку Си
Типизация: статическая слабая явная.
«Простые» типы:
_Bool (bool) – начиная с С99 - #include <stdbool.h>
char, signed char, unsigned char
short
int
long
long long
float, double, long double
void
указатели
Композитные: массивы, структуры, объединения
Функции
Выражения
Подробности:
Читать Стандарт языка (С89, С99, …)
Искать на stackoverflow.comПросто писать программы!
Статическая / динамическая типизация. Статическая определяется тем, что конечные типы переменных и функций устанавливаются на этапе компиляции. Т.е. уже компилятор на 100% уверен, какой тип где находится. В динамической типизации все типы выясняются уже во время выполнения программы.
Примеры:
Статическая: Cи, Java, C#; Динамическая: Python, JavaScript, Ruby.
Сильная / слабая типизация (также иногда говорят строгая /
нестрогая). Сильная типизация выделяется тем, что язык не позволяет смешивать в выражениях различные типы и не выполняет автоматические неявные преобразования, например нельзя вычесть из строки множество. Языки со слабой типизацией выполняют множество неявных преобразований автоматически, даже если может произойти потеря точности или преобразование неоднозначно.
Примеры:
Сильная: Java, Python, Haskell, Lisp; Слабая: Cи, JavaScript, Visual Basic, PHP.
Явная / неявная типизация. Явно-типизированные языки отличаются тем, что тип новых переменных / функций / их аргументов нужно задавать явно. Соответственно языки с неявной типизацией перекладывают эту задачу на компилятор / интерпретатор.
Примеры:
Явная: C++, D, C#
Неявная: PHP, Lua, JavaScript
Также нужно заметить, что все эти категории пересекаются, например язык Cи имеет статическую слабую явную типизацию, а
язык Python — динамическую сильную неявную.
21

|
|
«Чудеса» Си. И как с этим жить |
«Чудо» первое: размеры типов |
«Чудо» второе: поведение |
|
Тип: |
Размер в битах: |
|
char |
не менее 8 |
|
short |
не менее 16 |
|
int |
не менее 16 |
|
long |
не менее 32 |
|
long long |
не менее 64 |
|
Как жить с этим чудом?
Использовать типы с известной длиной!
#include <stdint.h>
char – чтобы хранить символы (а не числа)int8_t – знаковый 8 бит
uint8_t – беззнаковый 8int16_t – знаковый 16 бит
uint16_t – беззнаковый 16 бит и т.д. вплоть до 64
Компиляторы не всегда предупреждаютКомпиляторы не всегда следуют стандарту
Как жить с этим чудом?
Не выключать предупреждения (warning)
ЧИТАТЬ предупреждения! Ценить, что они вообще есть.
Помнить, что отсутствие предупреждений не означает, что все хорошо.
22

«Чудеса» Си. И как с этим жить
«Чудо» третье, неожиданное
Если поведение определенное, это еще не значит, что оно очевидное.
Примеры:
Правила неявного преобразования типовПриоритеты операторов
Арифметика с плавающей точкой (не только в Си!)МакросыУказатели, указатели, указатели..
Компиляция с оптимизацией усиливают чудеса!
Как жить с чудесами?
Учиться, учиться и еще раз учиться.
Или искать другой язык.
В каждом языке есть свои чудеса!
Аргументы критиков Cи
Компиляторы не всегда предупреждают
Компиляторы не всегда следуют стандарту
Как жить с этим чудом?
Не выключать предупреждения (warning)
ЧИТАТЬ предупреждения! Ценить, что они вообще есть.
Помнить, что отсутствие предупреждений не означает, что все хорошо.
Абстрактная машина языка Cи слишком похожа на устаревшую архитектуру PDP-11, которая давно уже не соответствует устройству популярных современных процессоров.
Несоответствие абстрактной машины Cи устройству реальных машин усложняет разработку оптимизирующих компиляторов языка.
Неполнота и сложность стандарта языка Си ведут к разночтениям в реализациях стандарта.
Доминирование Cи-подобных языков не позволяет исследовать альтернативные архитектуры процессоров.
Архаичная библиотека функций, запутанный и противоречивый стандарт, грубые ошибки в дизайне.
Но, судя по всему, кое-что создатели языка всё же сделали правильно.
Так или иначе, по-прежнему нужен язык низкого уровня, причём построенный именно для популярных фоннеймановских компьютеров.
И пускай Cи «устарел», но, видимо, любому его преемнику всё равно придётся отталкиваться от тех же самых принципов.
23

|
…и ещё одна классификация типов данных Си |
|
|
|
|
Типы данных Си |
|
Адресные |
Структурированные |
||
Указатель |
Ссылка (С++) |
Нерегулярные |
Регулярные |
|
|
Простые |
|
Целые |
Bool |
void |
С плавающей точкой |
(Си99) |
signed |
unsigned |
enum |
float |
double |
long |
|
|
|
double |
||
|
|
|
|
|
|
|
|
|
|
|
|
char |
|
short |
|
int |
|
long |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24

Небольшой список из популярных языков программирования
Язык |
|
Типизация |
|
JavaScript |
Динамическая |
Слабая |
Неявная |
Ruby |
Динамическая |
Сильная |
Неявна |
Python |
Динамическая |
Сильная |
Неявная |
Java |
Статическая |
Сильная |
Явная |
PHP |
Динамическая |
Слабая |
Неявная |
Cи |
Статическая |
Слабая |
Явная |
C++ |
Статическая |
Слабая |
Явная |
Perl |
Динамическая |
Слабая |
Неявная |
Objective-C |
Статическая |
Слабая |
Явная |
C# |
Статическая |
Сильная |
Явная |
Haskell |
Статическая |
Сильная |
Неявная |
Common Lisp |
Динамическая |
Сильная |
Неявная |
D |
Статическая |
Сильная |
Явная |
Delphi/Pascal |
Статическая |
Сильная |
Явная |
Примечания к таблице:
C# — поддерживает динамическую типизацию, посредством специального псевдо-типа dynamic с версии 4.0.
Поддерживает неявную типизацию с помощью dynamic и var.
С++ — после стандарта C++11 получил поддержку неявной типизации с помощью ключевых слов auto и decltype. Поддерживает динамическую типизацию, при использовании библиотеки Boost (boost::any, boost::variant). Имеет черты как сильной так и слабой типизации.
Common Lisp — стандарт предусматривает декларации типов, которые некоторые реализации могут использовать также для статической проверки типов.
D — также поддерживает неявную типизацию.
Delphi/Pascal — поддерживает динамическую типизацию посредством специального типа Variant.
25
Выводы
Система типов — совокупность правил в языках программирования, назначающих свойства, именуемые типами, различным конструкциям, составляющим программу — таким как переменные, выражения, функции или модули.
Основная роль системы типов заключается в уменьшении числа багов в программах посредством определения интерфейсов между различными частями программы и последующей проверки согласованности взаимодействия этих частей.
Эта проверка может происходить статически (на стадии компиляции[en]) или динамически (во время выполнения), а также быть комбинацией обоих видов.
Пример простой системы типов можно видеть в языке Си. Части программы на Си оформляются в виде определений функций. Функции вызывают друг друга.
Интерфейс функции задаёт имя функции и список значений, которые передаются её телу. Вызывающая функция постулирует имя функции, которую хочет вызвать, и имена переменных, хранящих значения, которые требуется передать.
Во время исполнения программы значения помещаются во временное хранилище, и затем исполнение передаётся в тело вызываемой функции. вызываемой функции осуществляет доступ к значениям и использует их.
Если инструкции в теле функции написаны в предположении, что им на обработку должно быть передано целое значение, но вызывающий передал число с плавающей точкой, то вызванная функция вычислит неверный результат.
Компилятор Си проверяет типы, заданные для каждой переданной переменной, в отношении к типам, заданным для каждой переменной в интерфейсе вызываемой функции. Если типы не совпадают, компилятор порождает ошибку времени компиляции.
Технически, система типов назначает тип каждому вычисленному значению и затем, отслеживая последовательность этих вычислений, предпринимает попытку проверить или доказать отсутствие ошибок согласования типов. Конкретная система типов может определять, что именно приводит к ошибке, но обычно целью является предотвращение того, чтобы операции, предполагающие определённые свойства своих параметров, получали параметры, для которых эти операции не имеют смысла — предотвращение логических ошибок. Дополнительно это также предотвращает ошибки адресации памяти.
Системы типов обычно определяются как часть языков программирования и встраиваются в их интерпретаторы и компиляторы. Однако система типов языка может быть расширена посредством специальных инструментов[en], осуществляющих дополнительные проверки на основе исходного синтаксиса типизации в языке.
Компилятор также может использовать статический тип значения для оптимизации хранилища и для выбора алгоритмической реализации операций над этим значением.
Например, во многих компиляторах Си тип float представляется 32 битами, в соответствии со спецификацией IEEE для операций с плавающей точкой одинарной точности. На основании этого будет использоваться специальный набор инструкций микропроцессора для значений этого типа (сложение, умножение и другие операции).
Количество налагаемых на типы ограничений и способ их вычисления определяют типизацию языка. Помимо этого, в случае полиморфизма типов, язык может также задать для каждого типа операцию варьирования конкретных алгоритмов.
Изучением систем типов занимается теория типов, хотя на практике конкретная система типов языка программирования основывается на особенностях архитектуры компьютера, реализации компилятора и общем образе языка.
26

27