]>Хранение информации в программе: переменные, константы и литералы

Хранение информации в программе: переменные, константы и литералы

Всё программирование сводится к тому, чтобы манипулировать какими‐нибудь данными. Данные хранятся не просто так «в воздухе», а физически размещаются в оперативной памяти компьютера. Области оперативной памяти, которым дали имя, — называются переменные и константы.

Типы данных

Когда ты начинаешь изучать новый язык программирования, одной из первых вещей, которую ты должны вызубрить, являются типы данных языка. Практически каждая программа управляет данными, и для правильного управления этими данными ты должен полностью понимать доступные типы. Ошибки неправильного использования типа данных занимают второе место по сравнению с синтаксическими ошибками, но они намного сложнее. Компилятор может отлавливать синтаксические ошибки и некоторые ошибки неправильного приведения типа данных, но большинство ошибок возникают уже во время работы программы и часто только при использовании определённых типов данных. Такие прерывистые ошибки трудно найти и их трудно исправить. Знание вида, размера и ограничений данных поможет свести такие ошибки к минимуму.

У FreeBASIC есть все стандартные числовые типы данных, которые ты ожидаешь для базового компилятора, а также указатели, которые обычно ты найдёшь только в языках низкого уровня, таких как Си.

Числовые типы данных

Знаковые типы данных могут содержать в себе ноль, отрицательные и положительные значения. Беззнаковые типы данных могут содержатьв себе только ноль или положительные значения. За счёт того, что один бит в числе используется для хранения знака (положительное или отрицательное число), диапазон максимальных и минимальных значений знаковых чисел в два раза меньше для соответствующих им беззнаковых чисел.

Знаковые целые

Числовые типы данныхЗанимаемый размер в памятиДиапазон
Byte8 бит, 1 байт, знаковыйОт -128 до 127
Short16 бит, 2 байта, знаковыйОт -32768 до 32767
Integer

32 бита, 4 байта на 32‐битной архитектуре, знаковый

64 бита, 8 байт на 64‐битной архитектуре, знаковый

На 32‐битной архитектуре от -2147483648 до 2147483647

На 64‐битной архитектуре от -9223372036854775808 до 9223372036854775807

Long32 бита, 4 байта, знаковыйОт -2147483648 до 2147483647
LongInt64 бита, 8 байт, знаковыйОт -9223372036854775808 до 9223372036854775807

Беззнаковые целые

Числовые типы данныхЗанимаемый размер в памятиДиапазон
UByte8 бит, 1 байт, беззнаковыйОт 0 до 255
UShort16 бит, 2 байта, беззнаковыйОт 0 до 65535
UInteger

32 бита, 4 байта на 32‐битной архитектуре, беззнаковый

64 бита, 8 байт на 64‐битной архитектуре, беззнаковый

На 32‐битной архитектуре от 0 до 4294967295

На 64‐битной архитектуре от 0 до 18446744073709551615

ULongInt64 бита, 8 байт, беззнаковыйОт 0 до 18446744073709551615
Ptr или Pointer

32 бита, 4 байта на 32‐битной архитектуре, беззнаковый

64 бита, 8 байт на 64‐битной архитектуре, беззнаковый

На 32‐битной архитектуре от 0 до 4294967295

На 64‐битной архитектуре от 0 до 18446744073709551615

Дробные типы

Типы данных с плавающей запятой, Single и Double могут хранить в себе дробные числа. Имей в виду, что такие числа подвержены ошибкам округления, которые накапливаются при длительных вычислениях. Очень плохая идея использовать такие числа для хранения денежных сумм.

Числовые типы данныхЗанимаемый размер в памятиДиапазон
Single32 бита, 4 байта, знаковыйЧисло с плавающей запятой одинарной точности, от 1.1E-38 до 3.43E+38
Double64 бита, 8 байт, знаковыйЧисло с плавающей запятой двойной точности, от -2.2E-308 до +1.7E+308

Логический тип

Этот тип данных может принимать только два значения: истину True или ложь False. Технически представляет из себя целое число, все биты которого либо сброшены в 0, либо установлены в 1.

Числовые типы данныхЗанимаемый размер в памятиДиапазон
Boolean8 бит, 1 байтМожет содержать в себе только одно из двух значений: истину True или ложь False

Из‐за того, что это число можно трактовать как знаковое, вытекает интересное наблюдение. Будем считать, что 0 — это ложь False, тогда истина True определяется как отрицание лжи. Отрицание нуля — это обращение всех бит числа на противоположное значение, то есть в единицу. Знаковое число со всеми установленными битами — это -1. Ложь False равна нулю, а истина True минус единице.

Какой тип данных выбрать

Существует несколько различных типов данных, как же выбрать правильный тип данных для любого конкретного приложения? Эмпирическое правило таково: использовать самый большой тип данных, который необходим для хранения ожидаемого диапазона значений. Это может показаться очевидным, но многие программы терпят неудачу, потому что программист не полностью понял диапазон данных в своей программе. Когда ты создаёшь программу, ты должен отображать не только логику программы, но и данные, связанные с каждым блоком логики. Когда ты наберёшь данные загодя, ты с меньшей вероятностью столкнёшься с ошибками типа данных.

Например, если ты работаешь с кодами ASCII, которые варьируются от 0 до 255, то UByte будет хорошим выбором, так как диапазон UByte совпадает с диапазоном кодов ASCII, и ты используешь только 1 байт памяти. Однако есть ещё одно соображение: «естественный» размер данных компьютера. В 32‐битной системе размер естественных данных составляет 4 байта или Integer. Это означает, что компьютер оптимизирован для обработки Integer и делает это более эффективно, даже если ты «теряешь» 3 байта памяти, используя Integer для кода ASCII.

В большинстве случаев Integer является хорошим универсальным выбором для целочисленных данных. Диапазон довольно велик, он обрабатывает как отрицательные, так и положительные числа, и тебе выгодно использовать естественный тип данных компьютера. Для данных с плавающей запятой Double является хорошим выбором, поскольку, как и Integer, он имеет хороший диапазон значений и лучшую точность, чем Single. Это только предложения; какой тип данных ты в конечном итоге используешь, будет определяться потребностями твоей программы.

Константы и литералы

Литералы

Литерал — это безымянная область памяти, которая не может изменяться. Это числа и строки, записанные в тексте программы как есть.

Число (числовой литерал) может быть записан в десятичном виде. А также шестнадцатеричном, восьмеричном и двоичном, используя специальные префиксы.

Система счисленияПрефиксПример
ДесятеричнаяОтсутствует234
Шестнадцатеричная&h или &H&hEA или &HEA
Двоичная&b или &B&b11101010 или &b11101010
Восьмеричная&o или &O&o352 или &O352

Константы

Константа — это именованная область памяти, которая не может изменяться.

Объявление

Константы объявляются в тексте программы через оператор Const по такой схеме:

Код FreeBASIC
Const ИмяКонстанты [ As ТипДанных ] = Литерал

Константу необходимо объявлять сразу же с инициализирующим её значением, иначе компилятор сообщит об ошибке.

Примеры

Код FreeBASIC
' Объявляем константу количества месяцев в году
Const MonthsInYear = 12

' Объявляем константу числа пи
Const Pi = 3.141592653

В данном примере MonthsInYear и Pi являются константами, а 12 и 3.141592356 — литералы.

Если попытаться присвоить константе какое‐нибудь значение, то это вызовет ошибку компиляции:

Код FreeBASIC
' Объявляем константу количества секунд в минуте
Const SecondsInMinute = 60

' Пробуем изменить её, но ничего не выходит:
SecondsInMinute = 70 ' ошибка компиляции

Объявлять можно не только числовые константы, но и строковые:

Код FreeBASIC
Const HelloWorld = "Привет, мир!"

HelloWorld — это константа, а строка "Привет, мир!" — литерал. Обрати внимание, что кавычки не являются частью литерала, а лишь ограничивают его. Как же в таком случае поместить кавычку внутрь литерала? Достаточно её удвоить:

Код FreeBASIC
Const QuotationLiteral = "Вот это "" кавычка внутри литерала"

Технически строковая константа представляет собой массив символов, в конце которого компилятор добавляет символ с кодом 0, чтобы программе можно было определить конец этого массива (конец строки).

Зачем нужны константы

Константы упростили процесс отладки и сопровождения программ:

Переменные

Переменная — это именованная область памяти, которую можно изменять.

Любая переменная должна быть объявлена до её использования. Переменные объявляются через операторы Dim и var.

Как правильно называть переменные

У любой переменной должно быть имя. Компилятор разрешает использовать в имени переменной только английские буквы, цифры и символ подчёркивания _, причём имя переменной не может начинаться с цифры.

Вот примеры правильных имён переменных:

А это примеры неправильных имён переменных, компилятор выдаст ошибку и откажется создавать программу:

У всех BASIC‐подобных языков есть одна особенность: большие и маленькие буквы в именах переменных, операторов и функций не различаются, поэтому компилятор будет считать Variable и vAriaBLE одним и тем же именем переменных.

Объявление переменных через оператор Dim

Переменные через оператор Dim объявляются по следующей схеме:

Код FreeBASIC
Dim ИмяПеременной As ТипДанных [ = Выражение]

Выражением может быть любой литерал, константа, результат выполнения функции или другая переменная. Единственное здесь условие: типы данных переменной и выражения должны совпадать.

Примеры:

Код FreeBASIC
' Объявляем целочисленную переменную
Dim x As Integer

' Также переменные можно объявлять сразу же вместе с начальным значением
Dim y As Integer = 35

В одной строке можно объявлять несколько переменных через запятую. В таком случае спецификатор типа следует указывать вначале:

Код FreeBASIC
Dim As Integer x, y

Если переменной не указывать инициализирующее значение, то она получит его по умолчанию. Для чисел — это ноль, для строк — это строка нулевой длины.

Объявление переменных через оператор var

Через оператор var переменные должны объявляться без указания типа данных, но сразу же с инициализирующим значением. Это не значит, что будет создана переменная без типа данных, просто тип переменной автоматически определится из инициализирующего выражения.

Код FreeBASIC
var ИмяПеременной = Выражение

Это удобно и немного сокращает код:

Код FreeBASIC
' Объявим переменную, в которой будет храниться длина
var length = 5

Через оператор var можно объявить несколько переменных сразу через запятую:

Код FreeBASIC
' Объявим несколько переменных в одной строке
var UserId = 251994, Rational = 2.54

Переменная UserId будет типа Integer, переменная Rational будет типа Double.

Указатели

Данные хранятся в памяти компьютера. Память можно представить как последовательный набор пронумерованных коробок начиная от нуля и размером в 1 байт. Обращаться к данным в этих коробках можно по их номеру.

Указатель — это переменная, которая хранит в себе «номер коробки» (адрес) где находятся данные.

Фактически, обычная переменная позволяет обращаться к данным по имени, а указатель — по номеру (адресу).

Объявление указателей

Указатель, как и любая переменная, должен быть объявлен. Они объявляются почти также, как и обычные переменные, но с добавлением ключевых слов Ptr или Pointer. Указатели можно объявлять через оператор Dim или var по таким схемам:

Код FreeBASIC
' Первый вариант
Dim ИмяУказателя As ТипДанных Ptr [ = Выражение]

' Второй вариант, менее распространён
Dim ИмяУказателя As ТипДанных Pointer [ = Выражение]

Указатель указывает на номер коробки, в которой хранятся данные определённого типа. Какого именно типа — определяется при объявлении указателя:

Код FreeBASIC
' Объявим указатель на целочисленные данные
Dim pInt As Integer Ptr

' Объявим указатель на байт
Dim pByte As Byte Ptr

' Можно объявлять указатель, который будет указывать на другой адрес, где хранятся данные
Dim pIntInt As Integer Ptr Ptr

Получение адреса переменной

Каждая переменная в памяти имеет свой адрес — номер первой коробки, где она расположена, а также своё значение. Как же получить адрес данных, которые хранятся в переменной?

Для этого существует оператор @ — он возвращает адрес объекта.

Код FreeBASIC
' Объявим целую переменную и запишем туда данные
Dim Days As Integer = 15

' Объявим указатель и получим адрес переменной
Dim pDays As Integer Ptr = @Days

' Распечатаем адрес
Print "pDays = "; pDays

_C:\WINDOWS\system32\cmd.exeC:\Program Files\FreeBASIC>Pointers.exepDays = 1375800C:\Program Files\FreeBASIC>_

Как видно, данные в переменной Days находятся в коробке номер 1375800. У тебя этот адрес наверняка будет другим, потому что программы могут загружаться в оперативную память по разным адресам.

Получение данных по адресу

Для того, чтобы извлечь данные, на которые ссылается указатель, существует оператор * — он возвращает данные по указателю. Такая операция называется «разыменование указателя». Не следует путать операцию разыменования и умножение, которое тоже обозначается звёздочкой.

Код FreeBASIC
' Объявим целую переменную и запишем туда данные
Dim Days As Integer = 15

' Объявим указатель и получим адрес переменной
Dim pDays As Integer Ptr = @Days

' Получим данные, которые хранятся по адресу указателя
Dim OriginalDays As Integer = *pDays
Print "OriginalDays = "; OriginalDays

' Распечатаем данные, на которые ссылается указатель
Print "*pDays = "; *pDays

' Перезапишем данные по указателю
*pDays = 20

' Посмотрим на оригинальную переменную, её значение будет изменено
Print "Days = "; Days

_C:\WINDOWS\system32\cmd.exeC:\Program Files\FreeBASIC>Pointers.exeOriginalDays = 15*pDays = 15Days = 20C:\Program Files\FreeBASIC>_

Типы данных переменной и указателя должны совпадать.

Нулевой указатель

При объявлении численной переменной без инициализации компилятор инициализирует её автоматически и помещает в неё 0. Указатель также является целочисленной беззнаковой переменной, поэтому он тоже будет инициализироваться нулём.

Код FreeBASIC
' Объявим указатель без инициализации
Dim pDays As Integer Ptr

' В нём находится ноль
Print "pDays = "; pDays

_C:\WINDOWS\system32\cmd.exeC:\Program Files\FreeBASIC>Pointers.exepDays = 0C:\Program Files\FreeBASIC>_

Ноль — это специальный зарезервированный адрес для указания особой области памяти, что указатель не ссылается на действительный адрес. При любой операции к такой памяти процессор генерирует специальное прерывание, операционная система перехватывает это прерывание и завершает вызвавший его процесс с ошибкой времени выполнения: «Программа выполнила недопустимую операцию и будет закрыта».

Разыменование нулевого указателя является операцией с неопределённым поведением. Это значит, что может произойти всё, что угодно: обращение к непредназначенной для использования данной программой памяти, запись в непринадлежащие программе данные, завершение процесса, зависание всей системы или что угодно другое.

Поэтому нельзя разыменовывать неинициализированные действительным адресом указатели.

Код FreeBASIC
' Так как указателю не присвоен действительный адрес
Dim p As Integer Ptr

' Так делать нельзя
Print *p

Упражнения

  1. Какой тип данных будет лучшим для хранения числа 196?
  2. Какой тип данных будет лучшим для хранения числа 2.134?
  3. Какой тип данных является наилучшим для общего использования в 32‐битных системах? А в 64‐битных системах?
  4. В чём разница между знаковыми и беззнаковыми типами данных?
  5. Какой префикс ты будешь использовать для обозначения двоичного числа?
  6. Какой префикс ты будешь использовать для обозначения шестнадцатеричного числа?
  7. Какие буквы допускаются в шестнадцатеричном числе?
  8. Дано шестнадцатеричное число: 1AF. Переведи в десятичное число.

Поделись ссылочкой в социальных сетях