Рейтинг:  5 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда активна
 

1.      Введение.

 

С выходом Clipper версии 5, в язык программирования Clipper добавились новые типы переменных – Static и Local. Старые типы переменных Public и Private остались, но использование их в большинстве случаев стало не оптимальным.

Данная статья пишется в 2006 году, когда язык Clipper уже не актуален, но так как в данный момент многие программы, написанные на Clipper, разработчики стали переводить под новый компилятор Xbase++, а всё описанное ниже справедливо и для Xbase++, возникла необходимость в освещении работы переменных.

 

2.      Отличия Public, Private и Static, Local переменных.

 

Public и Private переменные являются именованными переменными, т.е. после сборки и линковки программы в коде хранятся их имена, а в оперативной памяти создаётся таблица типа:

Имя Переменной

Значение переменной

Public1

Адрес области памяти со значением для Public1

Public2

Адрес области памяти со значением для Public2

Private1

Адрес области памяти со значением для Private1

И т.д.

 

 

 

При обращении к такой переменной происходит поиск по этой таблице необходимой переменной по её имени в  первом столбце, определяется адрес со значением  и выдаётся значение переменной из этого адреса. При изменении такой переменной – процесс аналогичен обращению.

 

 Static и Local переменные не являются именованными переменными, т.е. после сборки и линковки программы в коде хранятся прямые ссылки на области памяти с значением этих переменных.

 

Public,Private и Static,Local отличаются не только методом адресации, посмотрим на описание рассматриваемых переменных.

 

Оператор PUBLIC создает переменные и массивы, область видимости которых - все процедуры и функции пользователя в программе. PUBLIC переменные существуют до тех пор, пока процедура, в теле которой они определены, активна или пока они не будут уничтожены командами CLEAR ALL, CLEAR MEMORY, RELEASE. Когда PUBLIC переменные или массивы определены, любые уже существующие PRIVATE и PUBLIC переменные с такими же именами становятся невидимыми до тех пор, пока процедура не выполнится.

 

Оператор STATIC объявляет переменные и массивы, время жизни которых -

все время выполнения программы, а область видимости только внутри объекта, который их создал. STATIC переменные видны только внутри процедуры или функции пользователя, если они описаны после операторов PROCEDURE или FUNCTION. STATIC переменные видны во всех процедурах и функциях в программном (.prg) файле, если они объявлены перед первым описанием процедуры или функции пользователя в файле. Чтобы областью видимости переменных STATIC был весь файл, при его компиляции должна быть использована опция компилятора /N.

 

Из вышеприведённых описаний видно, что Public и Static переменные практически совпадают по времени жизни и отличаются только областью видимости. Заметим, что если вся программа помещается в одном PRG файле и переменные объявлены перед первым описанием процедуры или функции, то Public и Static переменные будут совпадать как областью видимости, так и временем жизни.

 

Оператор PRIVATE создает переменные и массивы, имеющие область видимости внутри текущей и вызываемых процедур и функций пользователя. Этот класс переменных имеет динамический контекст. PRIVATE переменные существуют до тех пор, пока процедура, где они описаны, активна или пока они не будут уничтожены командами CLEAR ALL, CLEAR MEMORY, RELEASE. При определении новых PRIVATE переменных или массивов любые уже существующие PRIVATE и PUBLIC переменные с таким же именем становятся невидимыми до тех пор, пока выполнение процедуры не закончится.

 

LOCAL - оператор объявления, который описывает одну или более переменных или массивов с областью видимости в текущей процедуре или функции, определенной пользователем, и должен находиться до первого исполняемого оператора, включая операторы PRIVATE, PUBLIC и PARAMETERS. Описание переменных делает невидимыми все унаследованные PRIVATE переменные и видимые PUBLIC переменные с такими же именами. Однако оператор LOCAL, который объявляет имя переменной, которая уже описана, приводит к фатальной ошибке компиляции и объектный файл не генерируется. Эта ошибка возникает как результат двух объявлений одинаковых имен переменных в одной и той же процедуре или при повторном объявлении переменной с областью видимости - весь файл. К этим операторам объявления относятся операторы FIELD, MEMVAR и STATIC.

 

LOCAL переменные имеют видимость только внутри текущей процедуры или функции, определенной пользователем, и в отличие от PRIVATE переменных не видны внутри вызываемых процедур. LOCAL переменные создаются автоматически каждый раз, когда процедура, в которой они были объявлены, выполняется. Они продолжают существовать и сохраняют свои значения до тех пор, пока объявляющая их процедура или функция пользователя не возвратит управление вызвавшей ее программе.

 

Из вышеприведённых описаний – видно, что Private и Local практически совпадают по времени жизни и отличаются только областью видимости, Local переменные не видны в вызываемых процедурах и функциях пользователя. Но в Clipper версии 5 добавлена новая операция - передача по ссылке (@).

 

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

 

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

 

Из описания операции передачи по ссылке (@) мы видим, что если Local переменную предавать во все вызываемые процедуры и функции пользователя, то область видимости Private и Local переменных будет одинаковой.

 

3.      Недостатки Public и Private переменных.

 

Public и Private переменные требуют оперативной памяти, так как для их использования создаётся таблица описанная в п.2 и чем больше количество используемых переменных, тем больше эта таблица и тем больше она занимает памяти. А располагать эта таблица должна в оперативной памяти и не свопироваться, так как обращение к ней происходит постоянно. Это очень важно при программировании под DOS, где оперативная память ограничена 640 килобайтами, но и при программировании под Windows используя Xbase++, где оперативная память ограничена физической памятью, всё равно не стоит разбрасываться такой вещью, как память.

 

Public и Private переменные работают гораздо медленнее, чем Static и Local, так как при обращении к ним происходит поиск по таблице, а при большом кол-ве переменных соответственно и таблица переменных может быть довольно большой и время поиска занимать приличное время.

 

Область видимости Public и Private переменных, хотя и более удобная в использовании, также является их недостатком, так как приводит к путанице и усложнению поддержки созданной программы. Особенно этот недостаток сказывается при написании большой программы коллективом разработчиков, когда Public переменные определённые одним разработчиком могут перекрываться Private переменными с такими же именами в модулях написанных другим разработчиком – отладить такую систему будет очень проблематично.

 

Public и Private переменные нарушают принципы модульности, поскольку чтобы понять принцип какого-то модуля, приходится вникать в детали всех тех процедур, из которых он вызывается. Это очень осложняет сопровождение программы, особенно если это приходится делать не разработчику программы.

 

4.      Когда без Public и Private переменных  не обойтись.

 

Пожалуй, единственным случаем, когда не обойтись без именованных переменных – это когда необходимо использовать переменные в макроподстановках и макровыражениях, поскольку имена Static и Local переменных не доступны во время выполнения.

 

5.      Как отказаться от использования Public переменных.

 

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

 

 

STATIC aPublic[10]

 

Func SetPublic (nVar,Item)

 

  if empty(nVar)

     Return (aPublic)

  endif

 

  do while Len(aPublic) < nVar

     AADD( aPublic , Nil )

  enddo

 

  if Item != NIL

    aPublic[nVar] := Item

  endif

 

Return aPublic[nVar]

 

С помощью функции SetPublic () можно из любой части программы получить доступ к переменной, передав в качестве первого параметра номер переменной, или изменить переменную, передав в качестве второго параметра новое значение переменной.

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

 

#define LEN_APUBLIC 3

 

#xtranslate PUB1 => SetPublic(1)

#xtranslate PUB1 := <Item> => SetPublic(1,<Item>)

 

#xtranslate PUB2 => SetPublic(2)

#xtranslate PUB2 := <Item> => SetPublic(2,<Item>)

 

#xtranslate PUB_PATH => SetPublic(3)

#xtranslate PUB_PATH := <Item> => SetPublic(3,<Item>)

 

 

6.      Как отказаться от использования Private переменных.

 

Private переменные можно заменить как и Public с помощью  Static переменных и специальных функций, но лучше для их замены использовать Local – переменные. Private и Local – переменные отличаются областью видимости – к Private-переменным мы имеем доступ не только в функциях в которых они определены, но и в вызываемых функциях. К Local – переменным мы так же можем получить доступ в вызываемых функциях, если передадим их в качестве параметра. Для того чтобы в вызываемых функциях иметь возможность изменять Local-переменные, их необходимо предавать по ссылке – оператор “@”  Пример использования передачи по ссылке:

 

 

Func main()

Local Test:=100

 

SubMain(@Test)

? Test         // Результатом будет - 200

 

Return (nil)

 

Func SubMain(Test)

Test := 200

Return (nil)

 

7.      Заключение.

 

Есть конечно и другие способы избавления от Private и Public переменных, в этой статье рассмотрены только основные способы. С выходом компилятора Xbase++ появилась возможность создания собственных классов, использование классов является хорошей альтернативой Private и Public переменным, но это уже тема для другой статьи.

 

 

Александр Есипов.

-