Файл: Понятие переменной в программировании. Виды и типы переменных (Понятие переменной. Типы данных переменной).pdf
Добавлен: 31.03.2023
Просмотров: 74
Скачиваний: 4
Формальным обоснованием для систем типов служит теория типов [7]. В состав языка программирования включается система типов для осуществления проверки типов во время компиляции или во время выполнения, требующая явного провозглашения типов или выводящая их самостоятельно.
Операция назначения типа, называемая типизацией, придаёт смысл цепочкам бит, таким как значение в памяти компьютера, или объектам, таким как переменная [7]. Компьютер не имеет возможности отличить, к примеру, адрес в памяти от инструкции кода, или символ от целого числа или числа с плавающей запятой, поскольку цепочки бит, представляющие эти различные по смыслу значения, не имеют каких-либо явных особенностей, позволяющих делать предположения об их смысле. Назначение цепочкам бит типа предоставляет это осмысление, превращая тем самым программируемое аппаратное обеспечение в символьную систему, состоящую из этого аппаратного обеспечения и программы.
Процесс проверки и установления ограничений для типов — контроль типов или проверка соответствия типов — может осуществляться как на стадии компиляции (статическая типизация), так и во время выполнения (динамическая типизация). Если спецификация языка требует, чтобы правила типизации исполнялись строго (то есть допуская в той или иной мере лишь те автоматические преобразования типов, которые не теряют информацию), такой язык называется сильно типизированным(англ. strongly typed; в русской литературе преобладает вариант перевода строго типизированным), в противном случае — слабо типизированным [7]. Эти термины являются условными и не используются в формальных обоснованиях.
Например, в языке Python [2] распределение памяти происходит в соответствии с присваиваемыми переменным значениями (динамическая типизация) [2]. Это означает, что переменная может содержать как целые числа, так и числа с плавающей точкой, текстовые строки или логические значения.
В настоящий момент времени большинство высокоуровневых языков программирования поддерживают концепцию объектно-ориентированного программирования. К типам данных можно также отнести классы.
То, что мы сейчас сказали про типы данных, характерно для большинства языков программирования. Более подробно про типизацию будет рассказано во второй главе данной курсовой работы.
Наглядно (см. рис. 3) переменную можно представить как коробочку, в которую можно положить на хранение что-либо. Имя переменной – это надпись на коробочке, значение – это то, что хранится в ней в данный момент, а тип переменной говорит о том, что допустимо класть в эту коробочку.
Рис. 3. Наглядное представление переменной в виде коробочки
В большинстве языков программирования, например в Python [2], переменной должно быть присвоено начальное значение (инициализация переменной) в инструкции, которая объявляет эту переменную, - иначе будет выдана ошибка, что переменная не определена.
Инициализация переменной на языке Python [2] будет выглядеть так, как показано на рис. 4.
Рис. 4. Инициализация сразу трех переменных на языке Python
На рис. 4 показан пример инициализации сразу трех переменных с одним и тем же значением. Знак равно в данном случае это не равенство, а оператор присваивания. Поместить в переменную значение можно при помощи оператора присваивания. Во многих языках программирования (С, С++, C#, Python, Java) он выглядит как знак =. В языке Паскаль он имеет обозначение :=. На рис. 5 показан пример инициализации переменных на языке C#, а на рис. 6 – инициализация переменных на языке Паскаль.
Рис. 5 Инициализация переменных на языке C#
Рис. 6. Инициализация переменных на языке Паскаль
Строго говоря, инициализировать переменные необходимо во всех языках программирования, это общее требование для любых программах. Однако, есть языки программирования, например Паскаль, где происходит автоматическая инициализация переменных (числовые переменные инициализируются значением нуль, строка инициализируется пустой строкой).
Любая переменная обладает еще двумя основными характеристиками: временем жизни и областью видимости [3]. Они зависят от места и способа описания переменной.
Если переменная описана вне любого блока (в частности, функции), она называется глобальной [3] и изначально обнуляется, если вы не предусмотрели ее инициализацию каким-то другим значением. Время её жизни – с начала выполнения программы и до её окончания, а область действия (область, в которой эту переменную можно использовать, обратившись к ней по имени) – весь файл, в котором она описана, начиная с точки описания [3].
Переменная, описанная внутри блока (в частности, внутри функции main), является локальной [3], память под неё выделяется в момент выполнения оператора описания и не обнуляется. Областью её действия является блок, в котором она описана, начиная с точки описания. Время её жизни также ограничено этим блоком [3]. Сколько раз выполняется блок, столько раз «рождается» и «умирает» локальная переменная.
Есть разновидность локальный переменных – статические [3]. Такие переменные существуют в языках программирования C++, C#, Java. Они, подобно глобальным переменным, существуют на всем протяжении выполнении программы и инициализируются однократно. С другой стороны, они, как локальные переменные, видны только в своем блоке. Для описания статических переменных используется ключевое слово static [3]. Ниже приведем пример описания трех переменных на языке C++ (см. рис. 7 и рис. 8).
Рис. 7. Описание различных переменных в языке С++
Рис. 8. Области видимости и время жизни переменных, язык С++
Память под все переменные из примера (рис. 7) выделяет компилятор. Кроме перечисленных существуют динамические переменные, память под которые резервируется во время выполнения программы [4] с помощью операции new в динамической области памяти. Доступ к таким переменным осуществляется не по имени, а через указатели [4].
Добавим еще то, что есть общая рекомендация, согласно которой не следует часто использовать глобальные переменные в своих программах. Переменная должна иметь минимальную из возможных областей действия, поскольку это значительно облегчает поиск ошибок [3].
Сделаем выводы по первой главе курсовой работы:
1. Под переменной в языках программирования понимают программный объект (число, слово, часть слова, несколько слов, символы), имеющий имя и значение, которое может быть получено и изменено программой [5].
2. Каждая переменная характеризуется следующими атрибутами [3]:
- именем;
- типом данных;
- значением;
- временем жизни;
- областью видимости.
3. Мы сформулировали общие правила именования переменных.
4. Дали определение понятию тип данных. Тип данных характеризует внутреннее представление, множество допустимых значений для этих данных, а также совокупность операций над ними [5]. Каждая переменная и константа программы должны принадлежать к определенному типу данных. Это необходимо для того, чтобы отвести необходимое место в оперативной памяти и для проверки правильности записи выражений. Например, над числовыми данными можно производить арифметические операции, а символьные данные используются для анализа текста.
5. Рассмотрели особенности работы глобальных и локальных переменных.
Вторая глава курсовой работы будет посвящена вопросам типизации.
ГЛАВА 2. Виды типизации в языках программирования
Для начала введем строгие определения.
Система типов данных языка — это система, которая ставит в соответствие каждому значению, вычисленному в процессе выполнения программы, свой тип данных [8].
Основные функции систем типов данных [8]:
- обеспечение безопасности: системы типов данных предотвращают так называемые «ошибки типов», проверяя, что каждая операция получает аргументы именно тех типов, для которых она имеет смысл, например, математические операции не получают аргументов типа строка или массив;
- оптимизация: типы, сопоставленные значениям, могут использоваться компилятором для оптимизации их обработки, например, для выбора способа их хранения и алгоритма их обработки;
- документация: использование определенных типов данных может подчеркивать намерения программиста;
- абстракция: использование типов данных высокого уровня позволяет программисту думать о значениях как о высокоуровневых сущностях, а не как о наборе битов.
Типизация языка определяется природой ограничений на типы данных и тем, как они проверяются и претворяются в жизнь. Типизация берет начало от практических вопросов архитектуры компьютеров, реализации компилятора и модели языка.
Языки программирования по типизации принято делить на два больших лагеря — типизированные и нетипизированные (бестиповые). К первому, например относятся C, Python, Scala, PHP и Lua, а ко второму — язык ассемблера, Forth и Brainfuck [5].
В бестиповых языках программирования — все сущности считаются просто последовательностями бит, различной длины [1]. Бестиповая типизация обычно присуща низкоуровневым (язык ассемблера, Forth) и эзотерическим (Brainfuck, HQ9, Piet) языкам. Однако и у нее, наряду с недостатками, есть некоторые преимущества [1].
Преимущества бестиповой типизации:
- позволяет писать на предельно низком уровне, причем компилятор / интерпретатор не будет мешать какими-либо проверками типов. Вы вольны производить любые операции над любыми видами данных;
- получаемый код обычно более эффективен;
- прозрачность инструкций. При знании языка обычно нет сомнений, что из себя представляет тот или иной код.
Так же существует сильная безтиповая типизация. Например в языке ассемблер [1] для архитектуры х86/х86-64 нельзя ассемблировать программу, если вы попытаетесь загрузить в регистр cx (16 бит) данные из регистра rax (64 бита).
Далее рассмотри понятия статической и динамической типизации.
Главное, что отличает статическую (static) типизацию от динамической (dynamic) то, что все проверки типов выполняются на этапе компиляции, а не этапе выполнения [5]. Компиляция – это процесс сборки программы, когда весь код на языке программирования высокого уровня переводится (транслируется) на язык машинных команд.
Некоторым может показаться, что статическая типизация слишком ограничена (на самом деле так и есть, но от этого давно избавились с помощью некоторых методик). Некоторым же, что динамически типизированные языки — это игра с огнем, так не ясно, какое именно значение находится сейчас в переменной. Неужели оба вида имеют шансы на существование? Если нет, то почему много как статически, так и динамически типизированных языков? Давайте разберемся.
Преимущества статической типизации [5]:
- Проверки типов происходят только один раз — на этапе компиляции. А это значит, что нам не нужно будет постоянно выяснять, не пытаемся ли мы поделить число на строку (и либо выдать ошибку, либо осуществить преобразование).
- Скорость выполнения. Из предыдущего пункта ясно, что статически типизированные языки практически всегда быстрее динамически типизированных.
- При некоторых дополнительных условиях, позволяет обнаруживать потенциальные ошибки уже на этапе компиляции.
- Ускорение разработки при поддержке IDE (отсеивание вариантов, заведомо не подходящих по типу).
Преимущества динамической типизации [5]:
- Простота создания универсальных коллекций — куч всего и вся (редко возникает такая необходимость, но когда возникает динамическая типизация выручит).
- Удобство описания обобщенных алгоритмов (например сортировка массива, которая будет работать не только на списке целых чисел, но и на списке вещественных и даже на списке строк).
- Легкость в освоении — языки с динамической типизацией обычно очень хороши для того, чтобы начать программировать.
Самый важный аргумент за динамическую типизацию — удобство описания обобщенных алгоритмов. Давайте представим себе проблему — нам нужна функция поиска по нескольким массивам (или спискам) — по массиву целых чисел, по массиву вещественных и массиву символов. Как же мы будем ее решать? Решим ее на 3-ех разных языках: одном с динамической типизацией и двух со статической.
Алгоритм поиска возьмем один из простейших — перебор. Функция будет получать искомый элемент, сам массив (или список) и возвращать индекс элемента, или, если элемент не найден — (-1).