Переменные, типы и Операторы
Встроенные типы данных | Переменные | Область видимости |
Константы | Операторы | Приоритет операторов |
Встроенные типы данных
Специальная информация о числах с плавающей запятой (точкой) одинарной и двойной точности (Float и Double).Таблица базовых типов данных поддерживаемых Purebasic, с кратким описанием:
Тип Суффикс Использование памяти Диапазон значенийByte .b 1 байт от - 128 до +127 ASCII .a 1 байт от 0 до +255 Character .c 1 байт (в режиме ascii и только с компилятором 5.4x и ниже) от 0 до +255 Character .c 2 байта (в unicode режиме) от 0 до +65535 Word .w 2 байта от - 32768 до +32767 Unicode .u 2 байта от 0 до +65535 Long .l 4 байта от - 2147483648 до +2147483647 Integer .i 4 байта (в 32-разрядном компиляторе) от - 2147483648 до +2147483647 Integer .i 8 байтов (в 64-разрядном компиляторе) от - 9223372036854775808 до +9223372036854775807 Float .f 4 байта Зависит от соотношения целой и дробной части. Quad .q 8 байтов от - 9223372036854775808 до +9223372036854775807 Double .d 8 байтов Зависит от соотношения целой и дробной части. String .s Длина строки + 1 * (1 или 2 байта) Без лимита. Fixed String .s {Длина} Длина строки * (1 или 2 байта) Без лимита.
Тип данных - определяет, что именно представляют собой данные (строковые символы, диапазон числовых значений и тд.), как они хранятся в памяти, какие операции с ними можно выполнять.
PureBasic предусматривает 12 числовых типов данных, которые имеют различные характеристики, что позволяет для каждой конкретной задачи найти компромисс между потреблением памяти и ограничением значений. В том числе поддерживаются целочисленные типы данных и типы данных с плавающей запятой.
Среди целочисленных типов есть варианты "без знака", это Ascii (.a) и Unicode (.u).
Тип Character (.c) так же может использоваться в качестве типа "без знака", в unicode он является аналогом типа unicode (.u).
Разрядность типа Integer (.i) напрямую зависит от разрядности ОС и компилятора (32 или 64 бит), и составляет (32 или 64 бит) соответственно.
Типы данных с плавающей запятой (float и double) предназначены для хранения положительных и отрицательных чисел с плавающей запятой. Число с плавающей запятой хранится в форме мантиссы (значение числа без учёта порядка), и показателя степени (порядка). При этом число с плавающей запятой имеет фиксированную относительную точность и изменяющуюся абсолютную.
Преимущество представления чисел в формате с плавающей запятой над представлением в формате с фиксированной запятой (и целыми числами) состоит в том, что можно использовать существенно больший диапазон значений при неизменной относительной точности. В то же время невозможно сохранить очень большое число с высокой точностью.
Другим ограничением чисел с плавающей запятой является то, что они хранятся в памяти компьютера с некоторой ограниченной точностью в двоичной системе счисления, в то время как общепринятой в использовании является десятичная система счисления. Поэтому многие числа, которые точно записываются в десятичной системе, в двоичной системе можно записать только в виде бесконечной дроби. Например, числа наподобие 0.5, 0.25 или 0.125 хранятся точно, так как представляют из себя степень двойки, в то время как число 0.11 может храниться в таком виде: 0.10999999 (бесконечная дробь).
В связи с этим, категорически не рекомендуется напрямую сравнивать между собой два числа с плавающей запятой, так как такое сравнение не всегда является корректным. В то же время, такие числа можно сравнивать приближённо, то есть, ограничивая точность сравнения до определённого знака после запятой.
Пример: Сравнения между собой значений float и double:
Define q.f = 0.5, w.d = 0.5 If q = w Debug "равенство 1" ; значения 0.5, 0.25, 0.125 и тд. хранятся точно и их можно сравнивать напрямую. EndIf q.f = 0.7 w.d = 0.7 Debug "значения переменных 'q' и 'w' в двоичном представлении отличаются:" Debug q Debug w If q = w Debug "равенство 2" ; значения отличные от 0.5, 0.25, 0.125 и тд. хранятся не точно и их нельзя сравнивать напрямую. EndIf If Abs (q-w) < 0.000001 ; Но с точностью до определённого знака после запятой можно сравнивать любые значения. Debug "равенство 3" EndIf
Пример: Сравнения между собой значений double (или float):
Define.d tree = 3.0, x, y, z x = 1/tree y = 4/tree z = 5/tree If x+y = z ; так нельзя сравнивать (ни в double, ни в float сравнение не пройдёт) Debug "1/3 + 4/3 = 5/3" Else Debug "1/3 + 4/3 <> 5/3" EndIf Debug x+y ; Значения 'x'+ 'y' и 'z' в двоичном представлении отличаются... Debug z If Abs (x+y-z) < 0.000001 ; Так можно сравнить с точностью до определённого знака после запятой. Debug "1/3 + 4/3 = 5/3" Else Debug "1/3 + 4/3 <> 5/3" EndIf
Точность в двоичной системе характеризуется числом знаков после запятой, для float (32-бит) это 7-8 знаков после запятой, для double (64-бит) это 15-16 знаков после запятой, так что не удивляйтесь, если числа с бОльшим количеством знаков отклоняются от ожидаемого значения! Поэтому, если вам нужны более точные результаты при работе с числами с плавающей запятой, используйте для переменных тип double вместо float.
Как пример: используя тип float, мы можем представить расстояние от Земли до Солнца с точностью до 10 км, а с помощью типа double – с точностью до толщины человеческого волоса. И даже если взять просто координаты GPS, то тип float даст точность только 2,4 метра, так что если требуется точность GPS менее 1 метра, то уже придётся использовать тип double. Это относится к числам с плавающей запятой в целом, а не только к PureBasic.
Точный диапазон значений, который можно использовать для хранения в переменных с типами float и double для получения корректных результатов арифметических операций, выглядит следующим образом:
Float: + 1.175494e-38 до + 3.402823e+38
Double: + 2.2250738585072013e-308 до + 1.7976931348623157e+308
Больше информации о стандарте 'IEEE 754' Вы можете найти в Википедии.
Примечание: Числа с плавающей запятой (float и double) могут быть записаны как: 123.5e-20
Пример: Отображение значений с плавающей запятой:
a.f=0.1 b.f=0.5 c.f=0.9 Debug a ; Отобразит 0.10000000149012 Debug b ; Отобразит 0.5 Debug c ; Отобразит 0.89999997615814 value.d = 123.5e-20 Debug value ; Отобразит 0.000000000000000001235
Кроме числовых типов, Purebasic так же поддерживает строковый тип данных - String (.s), его значением является произвольная последовательность (строка) символов. Каждый объект такого типа (переменная, массив и тд.) может быть представлен с фиксированным количеством символов (с указанием количества в фигурных скобках {xx}, например: dim a.s{32}(10) ), либо иметь произвольную длину. В режиме ASCII каждый символ занимает 1 байт памяти, а в режиме Unicode 2 байта памяти.Примечание по Структурным типам данных.
Общее число байт занимаемых конкретной строковой переменной можно найти с помощью команды StringByteLength(), однако если строковая переменная принадлежит к типу Fixed String, то ключевое слово sizeof даст более точный результат, так как посчитает и все нулевые символы, которых в данном случае может быть множество.
Для обозначения строковой переменной вместо суффикса (.s) можно использовать символ ($) в качестве последнего символа имени такой переменной. В таком случае символ ($) становится неотъемлемой частью имени переменной и должен указываться не только при объявлении, но и при любом последующем обращении к этой переменной. Также необходимо учитывать, что имена 'a$' и 'a.s' будут принадлежать к различным строковым переменным.
Помимо Базовых типов, Purebasic предоставляет поддержку Структурных типов, которые могут быть определены пользователем с помощью ключевого слова Structure. Структурный тип является составным типом и внутри может содержать любые числовые типы вперемешку с типами String, Fixed String и даже другой Структуры. Более подробную информацию можно найти в главе о Структурах.Примечание по Указательному типу данных.
Также поддерживается особый Указательный тип, объекты объявленные с таким типом предназначены для хранения адреса памяти. Более подробную информацию об устройстве памяти и указателях можно найти в главе Указатели.Преобразования типов данных, используемые Purebasic в математических выражениях.
Purebasic можно охарактеризовать как язык со статической, неявной и слабой типизацией, на практике это означает:
Статическая типизация – означает, что конечные типы объектов (переменных, массивов и тд.) устанавливаются на этапе компиляции и во время работы изменяться не могут.
Неявная типизация – означает, что при использовании объектов (переменных, массивов и тд.) или параметров не обязательно указывать тип.
Слабая типизация – означает, что в математическом выражении можно смешивать операнды различных числовых типов, при этом будут происходить автоматические неявные преобразования типов данных. Иногда, результат такого выражения может не совпадать с ожиданиями, так как при составлении выражения не учитывались нюансы алгоритма преобразований. Например, строка: Debug 2/(2/3) ; выдаст ошибку деления на 0!
В качестве простых операндов в выражениях могут использоваться: целые и дробные числа, Константы, Переменные, а так же элементы Массивов, Связных списков и Хеш-карт. Выражения состоящие только из чисел и констант, вычисляются на этапе компиляции. Если в выражении присутствует хоть один операнд с неизвестным на момент компиляции значением (переменная, элемент массива и тд.), то всё это выражение будет вычисляться уже во время работы программы.
Выявленные правила преобразования типов данных, которые применяет Purebasic при вычислении математических выражений (тестировалось в 5.44 и 5.70):
1) Для вычисления выражений используются только три типа данных: основной тип Integer, более ёмкий тип quad и самый ёмкий тип double.
2) Тип Integer используется для вычисления с операндами типов Byte, Ascii, Character, Word, Unicode, Long и Integer, а так же целых чисел и целочисленных констант в выражениях где есть переменные.
3) Тип Quad используется для вычислений с операндами типа Quad, а так же с целыми числами и целочисленными константами в выражениях без переменных (это значит на этапе компиляции).
4) Тип Double используется для всех вычислений с плавающей запятой.
5) Начальный тип данных, используемый для вычисления выражения, задаётся целевой переменной (a.i =… здесь это тип ‘Integer’).
6) Выражение оценивается слева направо, при этом тип данных, используемый для вычисления частей выражения, поэтапно может изменяться, но только в сторону более ёмкого типа: integer < quad < double.
7) Операнд с более ёмким используемым типом, чем текущий используемый тип, заставляет Purebasic преобразовать в этот новый тип все операнды находящиеся правее в этом выражении, а так же операнды находящиеся левее, вычисление которых зависит от этого операнда (т.е. учитывается приоритет операций) или они являются числовыми множителями для данного операнда. (В этот пункт сведено множество правил связанных с синтаксическим разбором математического выражения, это сделано для упрощения.)
8) После вычисления выражения, значение результата преобразуется к типу целевой переменной, чтобы при этом избежать потерь точности или данных, тип целевой переменной должен быть достаточно ёмким для сохранения результата, например, тип Ascii сможет сохранить целые значения от 0 до 255.
9) При делении целого значения на другое целое, тип выражения не изменяется, и если текущий тип выражения целочисленный - результат от деления округляется вниз. Именно поэтому Debug 2/(2/3) ; выдаст ошибку деления на 0!
10) При преобразованиях числовых выражений (без переменных) компилятор применяет "округление 0.5 вверх" (1.2→1, 1.5→2, 2.5→3, 3.5→4, -1.2→-1...)
11) При преобразованиях выражений с переменными во время работы программы, применяется "округление 0.5 до ближайшего чётного" (1.2→1, 1.5→2, 2.5→2, 3.5→4, -1.2→-1...)
Пример: Варианты округления чисел с плавающей запятой.
Define three.f = 3, four.f = 4 i.i = 1.5 + 3.0 Debug i ; Округление во время компиляции (0.5 вверх), результат 5 j.i = 1.5 + 4.0 Debug j ; Округление во время компиляции (0.5 вверх), результат 6 k.i = 1.5 + three Debug k ; Округление во время работы программы (0.5 до ближайшего чётного), результат 4 l.i= 1.5 + four Debug l ; Округление во время работы программы (0.5 до ближайшего чётного), результат 6 End
Пример: Проверка использования типов Integer и Quad для целочисленных вычислений.
Define b.b = 100, a.a = 100, c.c = 100, w.w = 100 Define u.u = 100, l.l = 100, i.i = 100, q.q = 100 Debug b*b*b*b*b ; на 32-х битном компиляторе результат зашкаливает, на 64-х битном правильный, значит для вычислений Byte используется тип Integer! Debug a*a*a*a*a ; Тоже для Ascii. Debug c*c*c*c*c ; Тоже для Character. Debug w*w*w*w*w ; Тоже для Word. Debug u*u*u*u*u ; Тоже для Unicode. Debug l*l*l*l*l ; Тоже для Long. Debug i*i*i*i*i ; Тоже для Integer. Debug "_" Debug q*q*q*q*q ; на 32-х битном и 64-х битном компиляторе результат правильный, значит для вычислений Quad используется тип Quad! Debug 100*100*100*100*100 ; на 32-х битном и 64-х битном компиляторе результат правильный, значит для числовых выражений используется тип Quad! Debug 100*100*100*100*i ; на 32-х битном компиляторе результат зашкаливает, на 64-х битном правильный, значит используется тип Integer! Debug "_" Debug i*i*q*i*i ; Используем 1 операнд с типом Quad, все операнды справа и множители слева преобразуются в тип Quad. g.q= b*b*b*b*b ; Использование целевой переменной с типом Quad, преобразует все операнды выражения в тип Quad. Debug g End
Пример: Проверка использования типа double для всех вычислений с плавающей запятой.
f.f = 3.402823e+38 ; Макс значение для float. d.d = 1.7976931348623157e+308 ; Макс значение для double. Debug 1.7976931348623157e+308 * 1.7976931348623157e+308 ; Превышаем макс значение double, результат = + Infinity. Debug 3.402823e+38 * 3.402823e+38 ; Превышаем макс значение float, но не double, результат нормальный, значит используется double! Debug "" Debug d * d ; Превышаем макс значение double, результат = + Infinity! Debug f * f * f ; Превышаем макс значение float, но не double, результат нормальный, значит используется double! #cons1 =2 ; Объявление констант. #cons2 =3 h.d =0.0 ; Объявление переменных с типами double g.f =0.0 ; и float, используемых для изменения типа выражения. Debug h.d+ 2/3 ; Переменная h.d устанавливает для последующих операндов тип double. Debug g.f+ 2/3 ; Здесь используется переменная с типом float, точность одинаковая с double, значит реально для вычислений используется тип double! Debug g.f + #cons1 / #cons2 ; константы с числовым значением обрабатываются как числа. End
Пример: преобразования типа в выражениях с разными типами данных.
z.f = 0 n.i =4 a.i = 2/3 + 2/(1+2) + z.f ; вычисляется как: a.i = 0 + 0 + 0.0 = 0. b.i = 2/3.0 + 2/(1+2) + z.f ; вычисляется как: b.i = 0.66 + 0.66 + 0.0 = 1.33 = 1 c.i = z.f + 2/(1+2) + 2/3 ; вычисляется как: c.i = 0.0 + 0.66 + 0.66 = 1.33 = 1 d.i = z.f + 2/(1+2) + 2/3 + 2/3 ; вычисляется как: d.i = 0.0 + 0.66 + 0.66 + 0.66 = 1.98 = 2 f.i = 2/3 + 2/(1+2.0) + 2/3 ; вычисляется как: f.i = 0 + 0.66 + 0.66 = 1.33 = 1. x.i = 2/3 * 4 *2/(1+2.0) + 2/3 ; вычисляется как: y.i = 0.66 * 4.0 * 0.66 + 0.66 = 2.44 = 2. y.i = 2/3 * n *2/(1+2.0) + 2/3 ; вычисляется как: x.i = 0 * 4 * 0.66 + 0.66 = 0.66 = 1. h.i = 2/((1/1+1-1)+((1*1/1)+(0+1.0))) ; вычисляется как: h.i = 2.0/((1.0)+(1.0)+(1.0)) = 0.66 = 1. Debug a ; 0 Debug b ; 1 Debug c ; 1 Debug d ; 2 Debug f ; 1 Debug x ; 2 Debug y ; 1 Debug h ; 1 End
• В строке a.i = 2/3 + 2/3 + z.f начальный тип выражения будет integer (задаётся целевой переменной a.i). Действие (2/3) - это деление целого на другое целое число, это действие не изменяет тип выражения и результат округляется вниз, таким образом получается 2/3 = 0,66 = 0. Следующее действие (2/3) повторяет судьбу предыдущего. Последний операнд z.f является переменной с типом Float, что заставляет Purebasic перевести остаток выражения (только z.f) в тип Double. После вычисления выражения результат будет преобразован (с округлением) к типу integer, чтобы соответствовать целевой переменной a.i. Что приводит строку к виду: a.i = 0 + 0 + 0.0 = 0.
• В строке b.i = 2/3.0 + 2/3 + z.f второй операнд заменён на 3.0, это заставляет Purebasic изменить тип на Double у всех операндов находящихся правее, а также находящиеся левее, если они являются числовыми множителями для 3.0 или их вычисление зависит от 3.0. Другими словами все действия в этом выражении вычисляются в режиме Double, поэтому результаты промежуточных действий не округляется, а сохраняется до конца. После получения последнего результата, его тип будет преобразован (с округлением) к типу integer, чтобы соответствовать целевой переменной b.i. Что приводит строку к виду: b.l = 0.66 + 0.66 + 0.0 =1.33 = 1
• Таких же результатов можно добиться, если в начале выражения подставить слагаемое с требуемым типом, как сделано в строке c.i = z.f + 2/3 + 2/3. Здесь в начале выражения используется переменная с типом Float, это заставляет Purebasic изменить тип на Double у всех операндов находящихся правее… Что приводит строку к виду: c.i = 0.0 + 0.66 + 0.66 =1.33 = 1
• В строке f.i = 2/3 + 2/(1+2.0) + 2/3 операнд (2.0) заставляет Purebasic изменить тип на Double у всех операндов находящихся правее, а также находящихся левее, если они являются числовыми множителями для (2.0) или их вычисление зависит от (2.0). В данном выражении операнд (2.0) находится в скобках, а результат вычисления в скобках влияет на вычисление связанное с третьим операндом (2), таким образом тип Double, будет использован начиная с третьего операнда выражения. Что приводит строку к виду: f.i = 0 + 0.66 + 0.66 = 1.33 = 1.
• В строке x.i = 2/3 * 4*2/(1+2.0) + 2/3 операнд (2.0) изменяет тип на Double у всех операндов находящихся правее, а также находящихся левее, если они являются числовыми множителями для (2.0) или их вычисление зависит от (2.0). То есть у всех.
• В строке y.i = 2/3 * n *2/(1+2.0) + 2/3 операнд (2.0) изменяет тип на Double у всех операндов находящихся правее, а также находящихся левее, если они являются числовыми множителями для (2.0) или их вычисление зависит от (2.0). То есть не у всех, так как 'n' это не числовой множитель (а переменная), в результате тип Double будет использован только для части выражения: 2/(1+2.0) + 2/3.
• В строке h.i = 2/((1/1+1-1)+((1*1/1)+(0+1.0))) операнд (1.0) находящийся в конце выражения, изменяет используемый тип для всех операндов на Double, так как через промежуточные вычисления он влияет на самый первый операнд.
Имя переменной (идентификатор):
Используемый для вычислений тип данных влияет на скорость вычислений, поэтому даже простой перестановкой слагаемых можно как увеличить быстродействие программы, так и замедлить её. В целом тип Integer самый быстрый, типы Double и Quad чуть медленнее, на 32-х разрядном компиляторе преобразования из Integer в Quad может в разы замедлить вычисления…
Вовремя тестирования были выявлены недочёты и баги при преобразованиях, вероятно в будущем часть статьи будет переписана, но для версии 5.60 ситуация такова.
Например, попробуйте запустить на 64-х разрядной версии такой код:
Если у Вас не вышла ошибка: "Out of FPU registers", то возможно ситуацию уже исправили…a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 a.q = 10 * 10 + u.f *10 End
Переменные
Переменная– это именованная область оперативной памяти компьютера, которая может временно хранить данные во время работы программы. Переменная имеет атрибуты:
♦ Имя
♦ Тип
♦ Значение
♦ Адрес
♦ Область видимости
♦ Время жизни
Имя переменной задаётся программистом при создании программы и должно соответствовать данным требованиям:Значение переменной:
• Имя не должно начинаться с цифры и может состоять из латинских букв (a,s…), цифр (0,1...) и символов подчёркивания (_).
• Не может совпадать с зарезервированными словами, используемыми в Purebasic: IF, For, Next и др.
• Не должно содержать пробелов ( ), знаков пунктуации (.) , специальных символов (ß, ä, ö, ü...) или операторов (+,-...).
• Длина имени не должна превышать 128 символов.
• Имя строковой переменной может содержать знак ($) в качестве последнего символа имени, вместо использования суффикса (.s).
• Имя переменной-указателя должно содержать знак (*) в качестве первого символа имени.
Все символы в имени переменной являются значимыми, но их регистр не имеет значения, поэтому переменные "pure" и "PURE" считаются одной и той же переменной, с другой стороны, "PURE" отличается от "PURE1".
Допустимые имена переменных: "pure", "PURE", "_Pure" , "____", "IF7", "Fore"…
Недопустимые имена переменных: "7pure", "P U R E", "+Pure" , "äpu7re7", "IF"…
Использование осмысленных имен помогает документировать код программы и облегчает неизбежный процесс отладки.
Это данные, которые хранятся переменной. Способы хранения и обработки данных зависят от того, к какому типу они принадлежат. Например, если переменная имеет тип Word, то она может хранить целочисленное значение в диапазоне от -32768 до +32767. Переменные с типом String могут сохранять только значения в виде строки. Начальное значение переменной зависит от её типа и равно 0 либо 0.0 либо пустой строке. Обычно значение переменной присваивается знаком '=' (равно), но можно использовать сокращенные формы оператора присваивания: Value + 1 (сработает как Value = Value + 1).Тип переменной:
Определяет тип данных, которые может принять на хранение переменная. Тип переменной указывается суффиксом при объявлении переменной, например: Var.w будет означать, что переменная Var объявлена с типом Word, таким образом можно объявить переменную любого стандартного типа поддерживаемого PureBasic или структурного типа определяемого пользователем. Если суффикс не указан, будет использован тип по умолчанию. Также переменную можно объявить как указатель, используя символ "*" в качестве первого символа имени переменной, например: Global *Point. Такая переменная сможет хранить адрес объекта в памяти или другое целочисленное значение ограниченное рамками типа Integer. Переменная-указатель может быть объявлена со структурным типом, например Global *Points.Point, что позволит использовать её в качестве указателя для доступа к экземпляру данной структуры. Так как Purebasic является языком со статической типизацией, тип переменной после объявления не может быть изменён!Адрес переменной:
Адрес переменной – это номер ячейки памяти, где находится ее первый байт (самый младший), все последующие байты переменной всегда выстроены в памяти друг за другом (от младшего к старшему). Например, если переменная имеет тип Long (4 байта) и имеет адрес 91700, то её младший байт будет находиться по адресу 91700, а старший байт по адресу 91703. Общее число занимаемых байт конкретной переменной можно найти с помощью ключевого слова sizeof. Адрес переменной можно получить, подставив символ '@' перед именем переменной, он используется для низкоуровневого обращения к данным хранящимся в переменной. Более подробную информацию об устройстве памяти и указателях можно найти в главе Указатели.
Двумя важнейшими и взаимосвязанными параметрами определяющими доступность Переменной в той или иной части кода являются Область видимости и Время жизни переменной.
Область видимости - обозначает область программы, в пределах которой имя (идентификатор) некоторой переменной продолжает быть связанным с этой переменной и возвращать её значение. За пределами области видимости тот же самый идентификатор может быть связан с другой переменной, либо быть свободным (не связанным ни с какой из них).
Время жизни переменной – это период времени выполнения программы, в течение которого переменная существует и сохраняет своё значение. В Purebasic этот параметр обычно напрямую связан с областью видимости переменной.
По области видимости все переменные можно разделить на два типа: глобальные и локальные.
Глобальная переменная после объявления обычно становится доступной в любом месте кода данного пространства имён и существует на протяжении всего времени выполнения программы.
Область видимости локальной переменной обычно определяется местом её объявления. Это значит, что если переменная объявлена в процедуре, то её значение будет не доступно вне этой процедуры, и наоборот.
В то же время Purebasic позволяет объявлять переменные с различными сочетаниями области видимости и времени жизни, например можно сделать так, что локальная переменная объявленная в процедуре будет существовать и сохранять своё значение между вызовами процедуры, а глобальная переменная, объявленная в основном коде, может стать невидимой внутри конкретной процедуры. Для объявления переменных с подобными характеристиками Purebasic предоставляет несколько ключевых слов, это: Global, Define, Protected, Threaded, Shared и Static.
В результате, Вам доступны не просто глобальные и локальные переменные, а целых шесть подтипов переменных с различными характеристиками. В инструментах IDE поддерживающих просмотр переменных они имеют такие обозначения: Global, Local, Main, Threaded, Shared и Static. В верхней части инструмента показываются Переменные, Массивы, Связные списки и Хеш-карты основного кода, а в нижней части - подобные объекты доступные в текущей процедуре:
Global (глобальная) – это Глобальная переменная, которая может быть объявлена с помощью ключевого слова Global, в любом месте кода данного пространства имён (лучше в начале основного кода). Область её видимости распространяется на весь код данного пространства имён (от точки объявления), включая любые процедуры, за исключением случая использования в процедуре ключевых слов Protected или Static, которые локально ограничивают её видимость. Переменная Global существует на всём протяжении работы программы.
Local (локальная) – это Локальная переменная, которая может быть объявлена с помощью ключевого слова Define или Protected, в любой процедуре данного пространства имён, а так же в параметрах ключевого слова Procedure, при декларации процедуры. Если при объявлении с помощью Protected использовать имя уже существующей переменной Global, видимость этой переменной Global в данной процедуре будет приостановлена, от момента этого объявления до выхода из процедуры, при этом конфликта имён не будет. Так же переменную Local можно объявить "на лету". Область её видимости распространяется на текущую процедуру (от точки объявления). Переменная Local существует на протяжении работы процедуры.
Main (основная) – это Локальная переменная, которая может быть объявлена с помощью ключевого слова Define, в основном коде данного пространства имён, так же её можно объявить "на лету". Область её видимости распространяется на весь код данного пространства имён (от точки объявления), кроме любых процедур, за исключением случая использования в процедуре ключевого слова Shared, которое открывает доступ к этой переменной из процедуры. В этой процедуре такая переменная представится как Shared. Переменная Main существует на всём протяжении работы программы.
Threaded (потоковая) - это Глобальная переменная, которая может быть объявлена с помощью ключевого слова Threaded, в основном коде данного пространства имён (лучше в начале основного кода). Область её видимости распространяется на весь код текущего потока (от точки объявления), данного пространства имён, кроме процедур, выполняемых в других потоках. У каждого потока будет свой экземпляр переменной. Переменная Threaded основного потока существует на всём протяжении работы программы, а экземпляры остальных потоков (созданные вызовом функции CreateThread() ) – пока не завершится их поток.
Shared (разделяемая) – это Локальная переменная Main, которая ранее была объявлена в основном коде и с помощью ключевого слова Shared стала доступна в текущей процедуре. Если при использовании ключевого слова Shared ввести имя несуществующей переменной Main, то переменная Main с данным именем и типом будет объявлена автоматически (как "на лету"), и станет доступна в основном коде (как Main) и текущей процедуре (как Shared). Переменную Global так же можно использовать как Shared (бессмысленно). Переменные Main и Global существуют на всём протяжении работы программы.
Static (статичная) – это Локальная переменная, которая может быть объявлена с помощью ключевого слова Static, в любой процедуре данного пространства имён. Область её видимости распространяется на текущую процедуру (от точки объявления). Эта переменная существует на всём протяжении работы программы и сохраняет своё значение между вызовами процедур. Если уже существует переменная Global с таким же именем, видимость переменной Global в этой процедуре будет приостановлена, от момента объявления Static до выхода из процедуры.
Кроме перечисленных выше способов по управлению видимостью переменных, дополнительно можно использовать разделение кода на пространства имён.
Программа в Purebasic изначально имеет одно Глобальное пространство имён, где есть свои Локальные и Глобальные переменные (точнее шесть подтипов), которые невидимы в дополнительных пространствах имён. При необходимости, Purebasic позволяет организовать в программе дополнительные пространства имён, в виде так называемых Модулей. Для предоставления доступа к переменным используемым в Модуле из других пространств имён, их необходимо объявить при создании модуля в специальном блоке команд DeclareModule / EndDeclareModule.
Сводная таблица характеристик Переменных в Purebasic:
Название подтипа переменной. Ключевое слово для объявления подтипа. Область видимости. Видимость в основном коде. Видимость в процедурах. Видимость в потоковых процедурах. Видимость в других пространствах имён. Возможность объявления "на лету". Время жизни. Global. Global. Глобальная. Да. Да. Да. Нет. Нет. Глобальное. Local. Define, Protected, Procedure. Локальная. Нет. Только в своей процедуре. Только в своей процедуре. Нет. Да. Только в своей процедуре. Main Define. Локальная. Да. Нет. Нет. Нет. Да. Глобальное. Threaded. Threaded. Глобальная. Да. Да. Для каждого потока свой экземпляр. Нет. Нет. В пределах своего потока. Shared. Shared. Локальная. Да. Только в своей процедуре. Только в своей процедуре. Нет. Нет. Глобальное. Static Static Локальная Нет Только в своей процедуре. Только в своей процедуре. Нет. Нет. Глобальное.
Объявление переменной в коде можно делать явно (с помощью ключевых слов), или "на лету" (без ключевых слов). При использовании выше названных ключевых слов допускается объявление сразу нескольких переменных в одной строке, через запятую. Например: Define.w a.d, b=1, c.s=" ". В этом случае с помощью суффикса (после ключевого слова) можно указать тип по умолчанию для переменных в этой строке, он сработает, если для какой либо из них тип не указан индивидуально. Если тип по умолчанию для этого объявления не указан, будет использован тип Integer. Так же, при объявлении переменным сразу можно присвоить значения (только посредством ‘=’, и кроме ключевого слова Shared).
Объявление "на лету" возможно только для Локальных переменных Main и Local, оно происходит автоматически при первом обращении к конкретной переменной, здесь же с помощью суффикса можно указать тип переменной, либо будет использован тип Integer. При объявлении "на лету", значение переменным можно присваивать не только с помощью ‘=’, но и используя сокращённые формы оператора присваивания.
Чтобы избежать ошибок ввода и т.д., можно заставить PureBasic всегда требовать "явного" объявления переменных, перед их использованием. Это делается с помощью применения в коде ключевого слова EnableExplicit.
При этом необходимо помнить, что Purebasic это компилятор, и все переменные (и др. именованные объекты) объявляемые в коде, будут занесены в пространство имён ещё на этапе компиляции (до начала программы), а присвоение значения этим переменным происходит во время работы программы. Например, если команда Define (Global, Threaded и тд.) помещена внутрь конструкции "If a>10 : Define Var.w=20 : Endif", то ещё до начала программы будет установлено, что в этой строке объявляется переменная Var.w, при этом условие a>10 может быть проверено только во время работы программы, следовательно, переменная Var.w будет считаться объявленной раньше, чем произойдёт проверка условия a>10 !!! Другими словами: команда Define Var.w=20 объявит переменную Var.w вне зависимости от выполнения условия a>10. В то же время, значение (20) переменная получит только после выполнения условия a>10, что может вносить путаницу.
Это относится к объявлению переменных в любых языковых конструкциях (циклы, процедуры, ветвления…). Компилятор с активированным режимом EnableExplicit, так же считает такие объявления легальными. Для проверки условий на стадии компиляции существуют специальные директивы компилятора (например CompilerIf : CompilerEndIf), но они могут работать только с константами и числами.
Следует отметить, что ключевые слова Global, Define, Protected, Threaded, Shared и Static и EnableExplicit распространяют своё действие только на текущее пространство имён, будь то глобальное пространство имён или Модуль.
Пример: "Не корректные" объявления переменных:
EnableExplicit ; Включение требования обязательного явного объявления переменных! Define a=5 If a>10 Define Var.w=20 ; Переменная считается объявленной здесь, хотя условие a>10 не выполнено !!! EndIf Procedure Change() Global b = 100 ; Переменная считается объявленной здесь, даже если процедуру никогда не вызовут !!! EndProcedure Debug Var ; Переменная ‘Var’ доступна, но значение 20 не присвоено, так как условие a>10 не выполнено. Debug b ; Переменная ‘b’ доступна, но значение 100 не присвоено, так как процедуру не вызывали. Change() Debug b ; После вызова процедуры переменная ‘b’ наконец-то получила значение 100
Пример: Объявление разделяемых (Shared) переменных в процедурах.
Define b.s = "стр. с суффиксом s", b${12} = "стр. с окончанием $" ; объявление локальных строковых переменных (Main). Define c = 30 ; Объявление локальной (Main) переменной 'c' с типом 'integer'. Procedure Change() Define z = 100 ; Объявление локальной (Local) переменной 'z' с типом 'integer'. Shared.w b,b$,c, e ; Объявление разделяемых (Shared) переменных. Переменные b,b$ и c теперь доступны в процедуре, а 'e' создаётся с типом 'word'. Debug c ; Будет 30, поскольку разделяемая переменная связана с переменной 'с' основного кода. e=50 Debug e ; Будет 50. Debug b Debug b$ ; Для этой переменной заявлено только 12 символов. EndProcedure Change() ; Вызов процедуры. Debug e ; Будет 50, поскольку в процедуре объявлена разделяемая (Shared) переменная 'e' и она видна в основном коде (как Main). Debug z ; Будет 0, поскольку вне процедуры значение переменной 'z' недоступно. End
Пример: Объявление защищенных (от основного кода) переменных в процедурах.
Global.w a=100, b=100 ; Объявление глобальных переменных (Global). Procedure qwe(v) ; Кроме декларации процедуры здесь также объявляется локальная (Local) переменная 'v' с типом 'integer'. Protected a ; Объявление локальной (local) переменной и приостановка видимости глобальной переменной 'a'. Static b ; Объявление локальной (Static) переменной и приостановка видимости глобальной переменной 'b'. a+20 ; Здесь используется сокращённая форма оператора присваивания. b=b+1 ; А здесь обычное присваивание. Debug a ; Эта переменная НЕ сохраняет свое значение между вызовами процедуры. Debug b ; Эта переменная СОХРАНЯЕТ свое значение между вызовами процедуры. EndProcedure For q=0 To 8 qwe(q) ; вызов процедуры Next q Debug a ; Содержимое переменных (Global) осталось нетронутым. Debug b ; То же самое End
Пример: Объявление переменных со структурным типом (структурированных).
Structure Test ; Создаём шаблон структуры. x.l ; Эти переменные являются полями структуры. y.l EndStructure Global var.Test, var2.Test ; Объявляем две переменных со структурным типом (типом определяемым пользователем). Debug "размер: " + SizeOf(Test) + " байтов" ; Размер в байтах, переменной с типом "Test" var.Test \x=1 ; Присваиваем данные полю x. var.Test \y=11 ; Присваиваем данные полю y. var2.Test \x=2 ; Присваиваем данные полю x во второй переменной. var2.Test \y=22 ; Присваиваем данные полю y во второй переменной. Debug var.Test \x ; Выводим данные на экран. Debug var.Test \y Debug var2.Test \x Debug var2.Test \y End
Пример: Объявление потоковых переменных.
Global a.l = 10 Threaded.l c = 30 ; объявление потоковой (Threaded) переменной. Если здесь задать значение, то оно будет в каждом потоке. c=200 ; задаём значение переменной для основного потока. Procedure Thread(f) Debug a ; Будет 10, поскольку переменная 'a' является глобальной (в любом потоке) Debug c ; Будет 30, при запуске в отдельном потоке и 200 в основном потоке (при простом вызове этой же процедуры). EndProcedure Thread = CreateThread(@Thread(), 0) ; запуск процедуры в отдельном потоке WaitThread(Thread) ; Ждём завершения потока. Thread(f) ; простой вызов процедуры End
Пример: Объявление переменных в модуле.
Global var = 50 ; Объявляем глобальную (Global) переменную в Глобальном пространстве имён. DeclareModule varmudul ; Декларация доступа к объектам модуля (доп. пространства имён). Define var1 = 100 ; Объявляем локальную переменную и делаем её доступной вне этого модуля. Global var2 = 200 ; Тоже с глобальной переменной EndDeclareModule Module varmudul Global var3 =300 ; объявляем глобальную переменную, приватную для этого модуля Debug var1 ; 100 Debug var2 ; 200 Debug var3 ; 300 Debug var ; здесь будет 0, так как переменная из Глобальном пространстве имён в модуле не доступна. EndModule Debug varmudul::var1 ; Здесь доступ к переменной есть. Будет 100. Debug varmudul::var2 ; Тоже. Будет 200. ;Debug varmudul::var3 ; Здесь будет ошибка, так как эта переменная не доступна вне модуля. Debug var ; здесь будет 50, так как эта строка в Глобальном пространстве имён и переменная доступна. End
Пример: Объявления переменных "на лету".
a.b = 20 ; Объявление "на лету" переменной 'a' с типом 'byte' и присвоение ей значения 20. *c= @a ; Объявление "на лету" переменной-указателя '*c' и присвоение ей значения адреса переменной 'a' b=a+30 ; Здесь переменная 'b' объявляется с типом по умолчанию непосредственно в выражении. e = 0 ; Объявление "на лету" переменной 'e' с типом по умолчанию Debug *c ; Адрес переменной 'a' хранящийся в указателе '*c' Swap e, b ; С помощью ключевого слова Swap можно быстро обменять содержимое двух однотипных переменных между собой. Debug e ; Результатом будет 50 d.s= "r2d"+1.1 ; При конкатенации строки и числа, число автоматически преобразуется в строку. Debug d EndДля действий с переменными (присвоение значений, объединение в выражения и тд.) можно использовать множество Операторов, которые будут описаны ниже.
Константы
Имя константы (идентификатор):
Константы похожи на переменные тем, что они обеспечивают простой способ обращения к данным по имени, но на этом сходство заканчивается. Если переменная служат для хранения изменяемых данных, то константа является псевдонимом некоторого значения, которое задаётся в программе один раз и более не изменяется. При компиляции программы, компилятор заменяет константы в коде на значения, которые те представляют. Использование констант упрощает процесс отладки программ, так как ошибки в именах (в отличии от чисел) обычно выявляются компилятором автоматически. Так же упрощается процесс внесения изменений, так как значение константы задано в программе всего в одном месте и его легко подправить.
Константы имеют атрибуты:
♦ Имя
♦ Тип
♦ Значения
♦ Область видимости
♦ Время жизни
Имя константы задаётся программистом при создании программы и должно соответствовать данным требованиям:Тип и Значение константы:
• Имя не должно начинаться с цифры и может состоять из латинских букв (a,s…), цифр (0,1...) и символов подчёркивания (_).
• Не должно совпадать с именами констант уже предопределённых в Purebasic, их имена можно увидеть в IDE инструменты/просмотр структур/константы.
• Не должно содержать пробелов ( ), знаков пунктуации (.) , специальных символов (ß, ä, ö, ü...) или операторов (+,-...).
• Длина имени константы не должна превышать 128 символов.
• Все имена констант имеют префикс (#), который служит обозначением константы и должен всегда указываться перед первым символом имени константы.
• Имя константы может содержать знак ($) в качестве последнего символа имени, для обозначения константы строкового типа.
Все символы в имени константы являются значимыми, но их регистр не имеет значения, поэтому константы "#cons" и "#CONS" считаются одной и той же константой, с другой стороны, "#CONS" отличается от "#CONS9".
Допустимые имена констант: "#CONS", "#cons", "#_Cons" , "#____", "#IF", "#For$"…
Недопустимые имена констант: "CONS ", "#c o n s", "#+Cons" , "#äpu7re7", " #PB_All"… (последнее имя допустимо, но оно уже используется в Purebasic)
Если имя константы допустимо, в редакторе IDE оно подсвечивается розовым цветом (по умолчанию).
Использование осмысленных имен помогает документировать код программы и облегчает неизбежный процесс отладки.
При объявлении константе можно присвоить значение любого числового или строкового типа, но только в виде конкретного числа, конкретной строки в кавычках или значения другой ранее объявленной константы. Не допускается для этого использовать значения переменных, возвращаемые значения функций и тд., то есть значения неизвестные на момент компиляции программы. Если в качестве последнего символа имени константы использовался знак ($), то такая константа будет считаться строковой и сможет принять только строковое значение.
Поскольку константе можно присвоить значение любого типа, при составлении выражений с константами, программист должен позаботиться о соответствии типа значения константы с типами других операндов выражения, так как Purebasic не позволяет смешивать в выражении строковые и числовые типы данных, кроме случая, когда происходит объединение строки и числового значения.
Пример: Константы в выражениях
Область видимости и время жизни константы:#cons$="abcde..." ; Объявление констант #cons="abcde..." #cons1=12345678.90 a.s = "Дом" + #cons$ ; ошибки нет. a.s = "Дом" + #cons1 ; ошибки нет, так как число преобразуется в строку автоматически. ;b.l = 100 + #cons ; будет ошибка, так как осуществляется попытка сложить числовое и строковое значение. b.l = 100 + #cons1 ; ошибки нет. Debug a.s
Область видимости константы всегда глобальна в пределах текущего пространства имён (глобального или модуля), даже если она объявлена в процедуре. Константа существует на протяжении всего времени выполнения программы. Для предоставления доступа к константам, используемым в модуле, их необходимо объявить при создании модуля в специальном блоке команд DeclareModule / EndDeclareModule.
Пример: Объявление константы в модуле
Объявление констант:#cons$="abcde..." ; Объявление констант #cons="abcde..." #cons1=123.49 a.s = "AAA " + #cons$ ; ошибки нет. Debug a.s b.l = 100 + #cons1 ; ошибки нет. Debug b.l ;b.l = 100 + #cons ; будет ошибка, так как осуществляется попытка сложить числовое и строковое значение.
Любую константу в коде можно объявлять только один раз, при этом требуется присвоить ей значение. Последующие объявления той же константы с тем же значением будут игнорироваться компилятором, это позволяет при необходимости объявлять константы в процедурах, и многократный вызов такой процедуры не будет приводить к ошибке. Если попытаться повторно объявить константу, но с другим значением, то компилятор ещё на стадии компиляции выдаст ошибку.
Пример: Объявление константы в коде.
#cons$ = "abcde..." ; объявление константы со строкой в качестве значения #cons = "abcde..." ; то же самое… #cons1 = 1234567890 ; объявление константы с числом в качестве значения. ;#cons2 = 12+33 +a ; будет ошибка, так как в присваиваемом выражении присутствует переменная.
Пример: Объявление константы в процедуре.
Procedure q() #cons = 12 #cons = 12 ; повторы объявления констант с тем же значением компилятор игнорирует… EndProcedure Debug #consЕсли Вам требуется объявить сразу несколько констант с последовательными числовыми значениями, то вы можете использовать команду Enumeration для перечисления (и объявления) констант.
Пример: Перечисление группы констант, с присваиванием значений начиная с 20 и шагом 3.
Enumeration 20 Step 3 #Const0 ; Будет 20 #Const1 ; Будет 23 #Const2 ; Будет 26 EndEnumerationДля перечисления констант подходящих в качестве флагов с битовыми значениями, можно использовать команду EnumerationBinary.
Пример: Перечисление группы констант, с присваиванием значений кратных двойке.
EnumerationBinary #Flags1 ; Будет 1 #Flags2 ; Будет 2 #Flags3 ; Будет 4 #Flags4 ; Будет 8 #Flags5 ; Будет 16 EndEnumerationБолее подробно про перечисления Вы можете почитать в главе Enumeration.
Для действий с константами (доступ к значению, объединение в выражения и тд.) служат множество операторов, которые описаны ниже. Единственное ограничение – присваивать значение константе можно только один раз, во время её объявления, и до конца программы изменять значение нельзя.
Операторы
Операторы- это функции, которые вы можете использовать в выражениях для объединения переменных, констант и всего остального. В приведенной ниже таблице показаны операторы, которые вы можете использовать в PureBasic, в любом порядке (LHS = Левая сторона, RHS = Правая сторона).
Оператор Описание / Пример =Равно. Это можно использовать двумя способами. Первое - присвоить значение выражения в RHS переменной в LHS. Второй способ - когда результат оператора используется в выражении и проверяет, совпадают ли значения выражений в LHS и RHS (если они одинаковы, этот оператор вернет истинный результат, в противном случае он будет Быть ложным).
Пример:
a=b+c; Присваивает значение выражения "b+c" к переменной "a"
If abc=def; Тестирует, совпадают ли значения abc и def и использует этот результат в команде If
При использовании со строками (string) '=' используется и как оператор присваивания, и как оператор сравнения. Примечание. Сравнение двух строк происходит с "учётом регистра"
Пример:
a$ = b$; Присваивает содержимое строки "b$" строке "a$" zu
If a$ = b$; Тестирует, совпадает ли содержимое строк a$ и b$, и использует этот результат в команде If
+Плюс. Получает результат от вычисления значения выражения в RHS, добавленного к значению выражения в LHS. Если результат этого оператора не используется и в LHS имеется переменная, значение выражения в RHS будет добавлено непосредственно к переменной в LHS
Пример:
number=something+2; Добавляет значение 2 к "чему-то" и использует результат с оператором "="
variable+expression; Значение "expression" будет добавлено непосредственно к переменной "variable"
Также "+" допустимо использовать со строками, для объединения содержимого двух строк, где результат будет присвоен строке в LHS с помощью оператора "=" или будет непосредственно сохранен в строке в LHS. Числовые значения также принимаются для комбинации со строкой. Это будет работать так же, как с использованием Str(), Str() или StrD() с их значениями по умолчанию для дополнительных параметров.
Пример:
a$ = b$ + "more"; Объединяет содержимое строки "b$" со строкой "more" и сохраняет это в строке "a$"
a$ + b$; Присоединяет содержимое строки "b$" непосредственно к строке "a$". a$ = b$ + 123
-Минус. Вычитает значение выражения в RHS из значения выражения в LHS. Если выражение LHS отсутствует, этот оператор дает отрицательное значение значения выражения в RHS. Если результат этого оператора не используется и в LHS имеется переменная, значение выражения в RHS будет вычитаться непосредственно из переменной в LHS. Этот оператор нельзя использовать с переменными строкового типа.
Пример:
var = #MyConstant - foo; Вычитает значение "foo" из "#MyConstant" и использует результат с оператором "="
another = another + - var; Вычисляет отрицательное значение "var" и использует результат в операторе "+"
variable - expression; Значение "expression" будет вычитаться непосредственно из переменной "variable"
*Умножение. Умножает значение выражения в LHS на значение выражения в RHS. Если результат этого оператора не используется и в LHS имеется переменная, то значение переменной непосредственно умножается на значение выражения в RHS. Этот оператор нельзя использовать с переменными строкового типа.
Пример:
total = price * count; Умножает значение "price" на значение "count" и использует результат с оператором "="
variable * expression; "variable" будет умножаться непосредственно значением "expression"
/Деление. Делит значение выражения в LHS на значение выражения в RHS. Если результат этого оператора не используется и в LHS имеется переменная, значение переменной непосредственно делят на значение выражения в RHS. Этот оператор нельзя использовать с переменными строкового типа.
Пример:
count = total / price; Делит значение "total" на значение "price" и использует результат с оператором "="
variable / expression; "Variable" будет разделена непосредственно значением "expression"
&Побитовое "И". Вы должны быть знакомы с двоичными числами при использовании этого оператора. Результатом этого оператора будет значение полученное путём применения операции Логическое "И" над каждым битом значений выражений в LHS и RHS. Бит результата устанавливается, если соответствующий бит установлен в обоих операндах, в соответствии с приведенной ниже таблицей. Кроме того, если результат оператора не используется и в LHS имеется переменная, результат будет сохранен непосредственно в этой переменной. Этот оператор нельзя использовать со строками.
LHS | RHS | Result ------------------ 0 | 0 | 0 0 | 1 | 0 1 | 0 | 0 1 | 1 | 1Пример:
; Показано использование двоичных чисел, поскольку так будет легче видеть результат
a.w = %1000 & %0101; Результат будет 0
b.w = %1100 & %1010; Результат будет %1000
bits = a & b; Логическое "И" с каждым битом a и b, и использование результата с оператором "="
a & b; Логическое "И" с каждым битом a и b, и сохранит результат непосредственно в переменной "a"
|Побитовое "ИЛИ". Вы должны быть знакомы с двоичными числами при использовании этого оператора. Результатом этого оператора будет значение полученное путём применения операции Логическое "ИЛИ" над каждым битом значений выражений в LHS и RHS. Бит результата устанавливается, если соответствующий бит установлен хотя бы в одном операнде, в соответствии с приведенной ниже таблицей. Кроме того, если результат оператора не будет использоваться и в LHS есть переменная, то результат будет сохранен непосредственно в той переменной. Этот оператор нельзя использовать со строками.
LHS | RHS | Result ------------------ 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 1Пример:
; Показано использование двоичных чисел, поскольку так будет легче видеть результат
a.w = %1000 | %0101; Результат будет %1101
b.w = %1100 | %1010; Результат будет %1110
bits = | b; Логическое "ИЛИ" с каждым битом a и b, и использование результата с оператором "="
a | b; Логическое "ИЛИ" с каждым битом a и b, и сохранит результат непосредственно в переменной "a"
!Побитовое "Исключающее ИЛИ". Вы должны быть знакомы с двоичными числами при использовании этого оператора. Результатом этого оператора будет значение полученное путём применения операции Логическое "Исключающее ИЛИ" над каждым битом значений выражений в LHS и RHS. Бит результата устанавливается, если соответствующий бит установлен в одном (но не в обоих) из двух операндов, в соответствии с приведенной ниже таблицей. Кроме того, если результат оператора не будет использоваться и в LHS есть переменная, то результат будет сохранен непосредственно в той переменной. Этот оператор нельзя использовать со строками.
LHS | RHS | Result ------------------ 0 | 0 | 0 0 | 1 | 1 1 | 0 | 1 1 | 1 | 0Пример:
; Показано использование двоичных чисел, поскольку так будет легче видеть результат
a.w = %1000! %0101; Результат будет %1101
b.w = %1100! %1010; Результат будет %0110
bits = a ! b; Логическое "Исключающее ИЛИ" с каждым битом a и b, и использование результата с оператором "="
a ! b; Логическое "Исключающее ИЛИ" с каждым битом a и b, и сохранит результат непосредственно в переменной "a"
~Побитовое "НЕ". Вы должны быть знакомы с двоичными числами при использовании этого оператора. Результатом этого оператора будет значение полученное путём применения побитовой Инверсии значения выражения в RHS. Значение каждого бита меняется на противоположное, в соответствии с приведенной ниже таблицей. Этот оператор нельзя использовать со строками.
RHS | Result ---------- 0 | 1 1 | 0Пример:
; Показано использование двоичных чисел, поскольку так будет легче видеть результат
a.b = ~ %1000; Теоретически результат будет% 0111, но на самом деле это% 11110111 (= -9, потому что байт со знаком).
b.b = ~ %1010; Теоретически результат будет% 0101, но на самом деле это% 11110101 (= -11, потому что байт со знаком)
()Скобки. Вы можете использовать наборы скобок, чтобы указать порядок вычисления выражения.
Пример:
a = (5 + 6) * 3; Результат будет 33, так как сначала вычисляется 5+6
b = 4 * (2 - (3 - 4)); Результат будет 12, так как сначала вычисляется 3-4, потом 2 - результат, потом умножение
<Меньше, чем. Этот оператор используется, для сравнения значений выражений в LHS и RHS. Если значение выражения в LHS будет меньше, чем значение выражения в RHS, то этот оператор даст результат - истина, в противном случае результат - ложь.
Пример:
If a < b; Тестирует, является ли значение а меньше чем b, и использует этот результат в команде If
Примечание: Сравнение строк всегда происходит с "учётом регистра". >Больше, чем. Этот оператор используется, для сравнения значений выражений в LHS и RHS. Если значение выражения в LHS будет больше, чем значение выражения в RHS, то этот оператор даст результат - истина, в противном случае результат - ложь.
Пример:
If a > b; Тестирует, является ли значение а больше чем b, и использует этот результат в команде If
Примечание: Сравнение строк всегда происходит с "учётом регистра". <=
=<Меньше чем или равно. Этот оператор используется, для сравнения значений выражений в LHS и RHS. Если значение выражения в LHS будет меньше чем или равно значению выражения в RHS, то этот оператор даст результат - истина, в противном случае результат - ложь. >=
=>Больше чем или равно. Этот оператор используется, для сравнения значений выражений в LHS и RHS. Если значение выражения в LHS будет больше чем или равно значению выражения в RHS, то этот оператор даст результат - истина, в противном случае результат - ложь. <>Не равно. Этот оператор используется, для сравнения значений выражений в LHS и RHS. Если значение выражения в LHS будет равно значению выражения в RHS, то этот оператор даст результат ложь, в противном случае результат - истина. ANDЛогическое "И". Может использоваться, чтобы объединить логические истинные и ложные результаты операторов сравнения, даёт результат показанный в следующей таблице.
LHS | RHS | Result ----------------------- false | false | false false | true | false true | false | false true | true | true ORЛогическое "Или". Может использоваться, чтобы объединить логические истинные и ложные результаты операторов сравнения, даёт результат показанный в следующей таблице.
LHS | RHS | Result ----------------------- false | false | false false | true | true true | false | true true | true | true XORЛогическое "исключающее ИЛИ". Может использоваться, чтобы объединить логические истинные и ложные результаты операторов сравнения, даёт результат показанный в следующей таблице. Этот оператор нельзя использовать со строками.
LHS | RHS | Result ----------------------- false | false | false false | true | true true | false | true true | true | false NotРезультатом этого оператора будет Логическое "НЕ" (инверсия) значения на RHS. Значение установлено согласно приведенной ниже таблице. Этот оператор нельзя использовать со строками.
RHS | Result --------------- false | true true | false <<Арифметический сдвиг влево. Сдвигает влево каждый бит в значении выражения в LHS, на количество разрядов, заданных значением выражения в RHS. Кроме того, когда результат этого оператора не используется, и LHS содержит переменную, то смещаться биты будут непосредственно у значения этой переменной. Сдвиг целого числа влево << на 1 разряд соответствует умножению числа на 2.
Пример:
a = %1011 << 1; Значение а будет %10110. %1011=11, %10110=22
b = %111 << 4; Значение b будет %1110000. %111=7, %1110000=112
c.l= 80 000 000$ << 1; Значение с будет равно 0. Биты сдвинутые за левый край результата теряются.
>>Арифметического сдвиг вправо. Сдвигает вправо каждый бит в значении выражения на LHS, на количество разрядов, заданных значением выражения на RHS. Кроме того, когда результат этого оператора не используется, и LHS содержит переменную, то смещаться биты будут непосредственно у значения этой переменной. Сдвиг целого числа вправо >> на 1 разряд соответствует делению числа на 2.
Пример:
d = 16 >> 1; значение d будет 8. 16 = %10000, 8 = %1000
e.w = %10101010 >> 4; значение e будет %1010. %10101010=170, %1010=10. Биты, смещенные из правого края результата теряются (причина, почему вы не видите равное деление на 16),
f.b = -128 >> 1; значение f будет -64. -128 = %10000000, -64 = %11000000. Смещаясь направо, старший значащий бит сохранен как есть
%По модулю. Возвращает остаток от целочисленного деления LHS на RHS.
Пример:
a = 16 % 2; значение будет 0, так как 16/2 = 8 (нет остатка)
b = 17 % 2; значение будет 1, так как 17/2 = 8*2+1 (1 остается),
Сокращения операторов
Каждый математический оператор может быть использован в сокращенной форме.
Пример
Value + 1 ; С тем же результатом можно использовать вместо: Value = Value + 1 Value * 2 ; С тем же результатом можно использовать вместо: Value = Value * 2 Value << 1 ; С тем же результатом можно использовать вместо: Value = Value << 1
Примечание. Это может привести к "неожиданным" результатам в некоторых редких случаях, если назначение изменено до присвоения.
Пример
Dim MyArray(10) MyArray(Random(10)) + 1 ; Аналогично: MyArray(Random(10)) = MyArray(Random(10)) + 1, ; но здесь Random() не будет возвращать одинаковое значение для каждого вызова!!!
Приоритет операторов
Уровень приоритета
Операторы
8 (выс.)
~, - (отрицательный)
7
<<, >>, %, !
6
|, &
5
*, /
4
+, - (вычитание)
3
>, >=, <, <=, =, <>
2
Not
1 (низ.)
And, Or, XOr